1. <?php
  2. /**
  3. * PEAR_PackageFileManager_Frontend, the singleton-based frontend for user input/output.
  4. *
  5. * PHP versions 4 and 5
  6. *
  7. * LICENSE: This source file is subject to version 3.01 of the PHP license
  8. * that is available through the world-wide-web at the following URI:
  9. * http://www.php.net/license/3_01.txt.  If you did not receive a copy of
  10. * the PHP License and are unable to obtain it through the web, please
  11. * send a note to license@php.net so we can mail you a copy immediately.
  12. *
  13. * @category   PEAR
  14. * @package    PEAR_PackageFileManager_Frontend
  15. * @author     Laurent Laville <pear@laurent-laville.org>
  16. * @copyright  2005-2006 Laurent Laville
  17. * @license    http://www.php.net/license/3_01.txt  PHP License 3.01
  18. * @version    CVS: $Id:$
  19. * @since      File available since Release 0.1.0
  20. */
  21.  
  22. require_once 'PEAR/PackageFileManager2.php';
  23. require_once 'PEAR/Config.php';
  24. require_once 'Config.php';
  25.  
  26. /**
  27. * @since  0.1.0
  28. * @access public
  29. */
  30. function realpathnix($path)
  31. {
  32.     if (!is_string($path)) {
  33.         $path = false;
  34.     } else {
  35.         $path = trim($path);
  36.         if (file_exists($path)) {
  37.             $path = str_replace(DIRECTORY_SEPARATOR, '/', realpath($path));
  38.             if (is_dir($path) && substr($path, -1, 1) !== '/') {
  39.                 $path .= '/';
  40.             }
  41.         } else {
  42.             $path = false;
  43.         }
  44.     }
  45.     return $path;
  46. }
  47.  
  48. /**
  49. * array_merge_recursive2()
  50. *
  51. * Similar to array_merge_recursive but keyed-valued are always overwritten.
  52. * Priority goes to the 2nd array.
  53. *
  54. * @param  array  $paArray1
  55. * @param  array  $paArray2
  56. * @return array
  57. * @static
  58. * @access public
  59. * @since  0.1.0
  60. * @author brian at vermonster dot com
  61. * @link   http://www.php.net/manual/en/function.array-merge-recursive.php#42663
  62. */
  63. function array_merge_recursive2($paArray1, $paArray2)
  64. {
  65.    if (!is_array($paArray1) or !is_array($paArray2)) {
  66.        return $paArray2;
  67.    }
  68.    foreach ($paArray2 as $sKey2 => $sValue2) {
  69.        $paArray1[$sKey2] = array_merge_recursive2(@$paArray1[$sKey2], $sValue2);
  70.    }
  71.    return $paArray1;
  72. }
  73.  
  74.  
  75. /**
  76. * Instance of PEAR_PackageFileManager_Frontend_{driver} class.
  77. *
  78. * @var    object
  79. * @since  0.1.0
  80. * @access private
  81. */
  82. $GLOBALS['_PEAR_PACKAGEFILEMANAGER_FRONTEND_SINGLETON'] = null;
  83.  
  84. /**#@+
  85. * Error Codes
  86. *
  87. * @since  0.1.0
  88. * @access public
  89. */
  90. define('PEAR_PACKAGEFILEMANAGER_FRONTEND_NODRIVER',        -1);
  91. define('PEAR_PACKAGEFILEMANAGER_FRONTEND_WRONG_LOGGER',    -2);
  92. define('PEAR_PACKAGEFILEMANAGER_FRONTEND_CANTOPEN_CONFIG', -3);
  93. define('PEAR_PACKAGEFILEMANAGER_FRONTEND_CANTCOPY_CONFIG', -4);
  94. define('PEAR_PACKAGEFILEMANAGER_FRONTEND_EMPTY_CONFIG',    -5);
  95. define('PEAR_PACKAGEFILEMANAGER_FRONTEND_WRONG_CONFIG',    -6);
  96. define('PEAR_PACKAGEFILEMANAGER_FRONTEND_NOOPTION',        -7);
  97. define('PEAR_PACKAGEFILEMANAGER_FRONTEND_WRONG_USERS',     -8);
  98. define('PEAR_PACKAGEFILEMANAGER_FRONTEND_NOUSER',          -9);
  99. define('PEAR_PACKAGEFILEMANAGER_FRONTEND_WRONG_USEROLE',  -10);
  100. /**#@-*/
  101. /**
  102. * Error messages
  103. *
  104. * @global array $GLOBALS['_PEAR_PACKAGEFILEMANAGER_FRONTEND_ERRORS']
  105. * @access private
  106. * @since  0.1.0
  107. */
  108. $GLOBALS['_PEAR_PACKAGEFILEMANAGER_FRONTEND_ERRORS'] =
  109.     array(
  110.         PEAR_PACKAGEFILEMANAGER_FRONTEND_NODRIVER =>
  111.             'No such driver "%driver%"',
  112.         PEAR_PACKAGEFILEMANAGER_FRONTEND_WRONG_LOGGER =>
  113.             'Logger must be compatible with PEAR::Log',
  114.         PEAR_PACKAGEFILEMANAGER_FRONTEND_CANTOPEN_CONFIG =>
  115.             'Loading preferences error: %error%',
  116.         PEAR_PACKAGEFILEMANAGER_FRONTEND_CANTCOPY_CONFIG =>
  117.             'Saving preferences error: %error%',
  118.         PEAR_PACKAGEFILEMANAGER_FRONTEND_EMPTY_CONFIG =>
  119.             'Your preference data source is empty. Uses all default values instead',
  120.         PEAR_PACKAGEFILEMANAGER_FRONTEND_WRONG_CONFIG =>
  121.             'Your preference data source is invalid. Uses all default values instead',
  122.         PEAR_PACKAGEFILEMANAGER_FRONTEND_NOOPTION =>
  123.             'Option "%option%" can\'t be located',
  124.         PEAR_PACKAGEFILEMANAGER_FRONTEND_WRONG_USERS =>
  125.             'No such list of users "%users%"',
  126.         PEAR_PACKAGEFILEMANAGER_FRONTEND_NOUSER =>
  127.             'User "%handle%" does not exists',
  128.         PEAR_PACKAGEFILEMANAGER_FRONTEND_WRONG_USEROLE =>
  129.             'Invalid user role "%role%"; must be one of "%valid%"',
  130.     );
  131.  
  132. /**
  133. * Singleton-based frontend for user input/output.
  134. *
  135. * This package is designed to be a backend to different front ends
  136. * written for the PEAR_PackageFileManager2 class.
  137. * For example, this package can be used to drive a PHP-GTK2 or web front end.
  138. *
  139. * @category   PEAR
  140. * @package    PEAR_PackageFileManager_Frontend
  141. * @author     Laurent Laville <pear@laurent-laville.org>
  142. * @copyright  2005-2006 Laurent Laville
  143. * @license    http://www.php.net/license/3_01.txt  PHP License 3.01
  144. * @version    Release: @package_version@
  145. * @since      Class available since Release 0.1.0
  146. */
  147.  
  148. class PEAR_PackageFileManager_Frontend
  149. {
  150.    /**
  151.     * Name of the frontend (driver), used to store the values in session
  152.     *
  153.     * @var     string
  154.     * @since   0.1.0
  155.     * @access public
  156.     */
  157.     var $driver;
  158.  
  159.     /**
  160.      * @var    string
  161.      * @since  0.1.0
  162.      * @access public
  163.      */
  164.     var $packagedirectory;
  165.  
  166.     /**
  167.      * @var    string
  168.      * @since  0.1.0
  169.      * @access public
  170.      */
  171.     var $pathtopackagefile;
  172.  
  173.     /**
  174.      * Contains the user settings preferences
  175.      *
  176.      * @var    object  PEAR::Config
  177.      * @since  0.1.0
  178.      * @access private
  179.      */
  180.     var $_conf;
  181.  
  182.     /**
  183.      * Instance of a log handler (class) that support a log() method
  184.      *
  185.      * @var    object
  186.      * @since  0.1.0
  187.      * @access private
  188.      */
  189.     var $_logger;
  190.  
  191.  
  192.     /**
  193.      * ZE1 class constructor
  194.      *
  195.      * @param  string  $driver              Name of the frontend (Web, Gtk2)
  196.      * @param  mixed   $packagedirectory    Path to the base directory of the package
  197.      * @param  mixed   $pathtopackagefile   Path to an existing package file to read in
  198.      * @access public
  199.      * @since  0.1.0
  200.      */
  201.     function PEAR_PackageFileManager_Frontend($driver, $packagedirectory, $pathtopackagefile)
  202.     {
  203.         $this->packagedirectory  = $packagedirectory;
  204.         $this->pathtopackagefile = $pathtopackagefile;
  205.         $this->driver  = $driver;
  206.         $this->_logger = false;
  207.     }
  208.  
  209.     /**
  210.      * Creates a unique instance of the given front end class.
  211.      *
  212.      * @param  string  $driver              Name of the frontend (Web, Gtk2)
  213.      * @param  mixed   $packagedirectory    Path to the base directory of the package
  214.      * @param  mixed   $pathtopackagefile   Path to an existing package file to read in
  215.      * @param  mixed   $logger              PEAR::Log or compatible instance
  216.      * @return PEAR_PackageFileManager_Frontend_{$driver}
  217.      * @access public
  218.      * @since  0.1.0
  219.      * @static
  220.      */
  221.     function &singleton($driver = '', $packagedirectory = false, $pathtopackagefile = false,
  222.                         $logger = false)
  223.     {
  224.         if (!isset($GLOBALS['_PEAR_PACKAGEFILEMANAGER_FRONTEND_SINGLETON'])) {
  225.             if ($logger) {
  226.                 $s =& PEAR_ErrorStack::singleton('@package_name@');
  227.                 $s->setLogger($logger);
  228.             }
  229.  
  230.             $uiclass = "PEAR_PackageFileManager_Frontend_$driver";
  231.  
  232.             if (!class_exists($uiclass)) {
  233.                 $file = str_replace('_', '/', $uiclass) . '.php';
  234.                 if (PEAR_PackageFileManager2::isIncludeable($file)) {
  235.                     include_once $file;
  236.                 }
  237.             }
  238.             if (!class_exists($uiclass)) {
  239.                 $err =& PEAR_ErrorStack::staticPush('@package_name@',
  240.                     PEAR_PACKAGEFILEMANAGER_FRONTEND_NODRIVER, 'error',
  241.                     array('driver' => $driver),
  242.                     $GLOBALS['_PEAR_PACKAGEFILEMANAGER_FRONTEND_ERRORS'][PEAR_PACKAGEFILEMANAGER_FRONTEND_NODRIVER]
  243.                     );
  244.                 return $err;
  245.             }
  246.             $fe =& new $uiclass($driver, $packagedirectory, $pathtopackagefile);
  247.             if ($logger) {
  248.                 $fe->setLogger($logger);
  249.             }
  250.             $GLOBALS['_PEAR_PACKAGEFILEMANAGER_FRONTEND_SINGLETON'] =& $fe;
  251.         }
  252.         return $GLOBALS['_PEAR_PACKAGEFILEMANAGER_FRONTEND_SINGLETON'];
  253.     }
  254.  
  255.     /**
  256.      * Set up a PEAR::Log object or compatible for this frontend
  257.      *
  258.      * @param  mixed   $logger              PEAR::Log or compatible instance
  259.      * @return TRUE on success, FALSE on error
  260.      * @access public
  261.      * @since  0.1.0
  262.      */
  263.     function setLogger(&$logger)
  264.     {
  265.         if (isset($logger) && (!is_object($logger) || !method_exists($logger, 'log'))) {
  266.             PEAR_ErrorStack::staticPush('@package_name@',
  267.                 PEAR_PACKAGEFILEMANAGER_FRONTEND_WRONG_LOGGER, 'warning',
  268.                 array(),
  269.                 $GLOBALS['_PEAR_PACKAGEFILEMANAGER_FRONTEND_ERRORS'][PEAR_PACKAGEFILEMANAGER_FRONTEND_WRONG_LOGGER]
  270.                 );
  271.             return false;
  272.         }
  273.         $s =& PEAR_ErrorStack::singleton('@package_name@');
  274.         $s->setLogger($logger);
  275.         $this->_logger = &$logger;
  276.         return true;
  277.     }
  278.  
  279.     /**
  280.      * Load the user preferences for this frontend
  281.      *
  282.      * @param  mixed    $config  a PEAR::Config container or an identification array
  283.      * @return TRUE on success, FALSE on error
  284.      * @access public
  285.      * @since  0.1.0
  286.      */
  287.     function loadPreferences(&$config)
  288.     {
  289.         // user options configuration (temporary)
  290.         $this->_conf = new Config();
  291.  
  292.         // source is Config_Container
  293.         if (strcasecmp(get_class($config), 'config_container') == 0) {
  294.             $root =& $this->_conf->getRoot();
  295.             $res =& $root->addItem($config);
  296.             $this->log('debug', 'Load preferences from a config_container');
  297.         // source is Array
  298.         } elseif (is_array($config)) {
  299.             list($source, $type, $options) = $config;
  300.             if (is_string($source)) {
  301.                 $this->log('debug', "Load preferences from file \"$source\" ($type)");
  302.             } else {
  303.                 $this->log('debug', "Load preferences from data stream ($type)");
  304.             }
  305.             if (!isset($options)) {
  306.                 // in case no parser options are given
  307.                 $options = array();
  308.             }
  309.             $res =& $this->_conf->parseConfig($source, $type, $options);
  310.             $root =& $this->_conf->getRoot();
  311.         }
  312.         if (PEAR::isError($res)) {
  313.             PEAR_ErrorStack::staticPush('@package_name@',
  314.                 PEAR_PACKAGEFILEMANAGER_FRONTEND_CANTOPEN_CONFIG, 'error',
  315.                 array('error' => $res->getMessage() ),
  316.                 $GLOBALS['_PEAR_PACKAGEFILEMANAGER_FRONTEND_ERRORS'][PEAR_PACKAGEFILEMANAGER_FRONTEND_CANTOPEN_CONFIG]
  317.                 );
  318.             return false;
  319.         }
  320.  
  321.         $pfmSection =& $root->getItem('section', 'pfm');
  322.         $guiSection =& $root->getItem('section', 'gui');
  323.  
  324.         if ($pfmSection || $guiSection) {
  325.             $attrs = $root->getAttributes();
  326.             // get user config version if available
  327.             if (!isset($attrs['version'])) {
  328.                 // or apply default value (API version)
  329.                 $attrs['version'] = '@api_version@';
  330.             }
  331.             $root->setAttributes(null);
  332.             $settings =& $root->createSection('root2', $attrs);
  333.  
  334.             if ($pfmSection) {
  335.                 $pfmSection->removeItem();
  336.                 $settings->addItem($pfmSection);
  337.             }
  338.             if ($guiSection) {
  339.                 $guiSection->removeItem();
  340.                 $settings->addItem($guiSection);
  341.             }
  342.         }
  343.  
  344.         $virtualRoot =& $root->getItem('section');
  345.         $virtualRoot->setName('settings');
  346.         $attrs = $virtualRoot->getAttributes();
  347.         // get user config version if available
  348.         if (!isset($attrs['version'])) {
  349.             // or apply default value (API version)
  350.             $attrs['version'] = '@api_version@';
  351.             $virtualRoot->updateAttributes($attrs);
  352.         }
  353.  
  354.         // By setting the new root, we will remove all others directives included on import.
  355.         // Only directives below 'pfm' and 'gui' sections are supported
  356.         $this->_conf->setRoot($virtualRoot);
  357.  
  358.         $directives = 0;
  359.         $pfmSection =& $virtualRoot->getItem('section', 'pfm');
  360.         if ($pfmSection && $pfmSection->countChildren() > 0) {
  361.             $directives++;
  362.         }
  363.         $guiSection =& $virtualRoot->getItem('section', 'gui');
  364.         if ($guiSection && $guiSection->countChildren() > 0) {
  365.             $directives++;
  366.         }
  367.  
  368.         if ($directives == 0) {
  369.             // no user preferences given, all defaults options are applied
  370.             PEAR_ErrorStack::staticPush('@package_name@',
  371.                 PEAR_PACKAGEFILEMANAGER_FRONTEND_EMPTY_CONFIG, 'warning',
  372.                 array(),
  373.                 $GLOBALS['_PEAR_PACKAGEFILEMANAGER_FRONTEND_ERRORS'][PEAR_PACKAGEFILEMANAGER_FRONTEND_EMPTY_CONFIG]
  374.                 );
  375.         } else {
  376.             $options = $virtualRoot->toArray();
  377.             $custom = $options['settings'];
  378.         }
  379.  
  380.         // default options
  381.         $pfm = new PEAR_PackageFileManager2();
  382.         $pfmOptions = $pfm->getOptions();
  383.         $default = array(
  384.             'pfm' => array(
  385.                 'roles'              => $pfmOptions['roles'],
  386.                 'dir_roles'          => $pfmOptions['dir_roles'],
  387.                 'changelogoldtonew'  => $pfmOptions['changelogoldtonew'],
  388.                 'simpleoutput'       => $pfmOptions['simpleoutput'],
  389.                 'exportcompatiblev1' => false,
  390.                 'baseinstalldir'     => '/',
  391.                 'outputdirectory'    => $pfmOptions['outputdirectory'],
  392.                 'package_type'       => array('php','extsrc','extbin'),
  393.                 'stability'          => array('snapshot','devel','alpha','beta','stable'),
  394.                 'maintainer_roles'   => array('lead','developer','contributor','helper'),
  395.                 'filelistgenerator'  => array('File', 'Cvs', 'Svn', 'Perforce'),
  396.                 ),
  397.             'gui' => array(
  398.                 'actions' => array('display' => 'ActionDisplay', 'process' => 'ActionProcess', 'dump' => false)
  399.                 )
  400.         );
  401.  
  402.         if (isset($custom)) {
  403.             $options = array_merge_recursive2($default, $custom);
  404.             $source = array('settings' => $options);
  405.         } else {
  406.             $source = array('settings' => $default);
  407.         }
  408.         // the final config
  409.         $this->_conf = new Config();
  410.         $this->_conf->parseConfig($source, 'phparray');
  411.         return true;
  412.     }
  413.  
  414.     /**
  415.      * Save the user preferences for this frontend
  416.      *
  417.      * @param  mixed   $target     Datasource to write to
  418.      * @param  string  $type       Type of configuration
  419.      * @param  array   $options    Options for config container
  420.      * @return TRUE on success, FALSE on error
  421.      * @access public
  422.      * @since  0.1.0
  423.      */
  424.     function savePreferences($target, $type, $options = null)
  425.     {
  426.         if (strcasecmp($type, 'xml') == 0) {
  427.             if (!is_array($options)) {
  428.                 settype($options, 'array');
  429.             }
  430.             $name = array('name' => '');
  431.             $options = array_merge($options, $name);
  432.         }
  433.         $out = $this->_conf->writeConfig($target, $type, $options);
  434.         if (PEAR::isError($out)) {
  435.             PEAR_ErrorStack::staticPush('@package_name@',
  436.                 PEAR_PACKAGEFILEMANAGER_FRONTEND_CANTCOPY_CONFIG, 'error',
  437.                 array('error' => $out->getMessage() ),
  438.                 $GLOBALS['_PEAR_PACKAGEFILEMANAGER_FRONTEND_ERRORS'][PEAR_PACKAGEFILEMANAGER_FRONTEND_CANTCOPY_CONFIG]
  439.                 );
  440.             return false;
  441.         }
  442.         return true;
  443.     }
  444.  
  445.     /**
  446.      * Gets a user preference node value using XPATH like format.
  447.      *
  448.      * @param  array    $xpath    search format
  449.      * @param  boolean  $asString return value as a simple string or native config container array
  450.      * @return mixed
  451.      * @access public
  452.      * @since  0.1.0
  453.      * @see    Config_Container::searchPath()
  454.      */
  455.     function getOption($xpath, $asString = true)
  456.     {
  457.         if (!is_array($xpath)) {
  458.             settype($xpath, 'array');
  459.         }
  460.  
  461.         $root =& $this->_conf->getRoot();
  462.         $directive =& $root->searchPath($xpath);
  463.  
  464.         if (!$directive) {
  465.             $option = implode('/', $xpath) ;
  466.             $err =& PEAR_ErrorStack::staticPush('@package_name@',
  467.                 PEAR_PACKAGEFILEMANAGER_FRONTEND_NOOPTION, 'warning',
  468.                 array('option' => $option),
  469.                 $GLOBALS['_PEAR_PACKAGEFILEMANAGER_FRONTEND_ERRORS'][PEAR_PACKAGEFILEMANAGER_FRONTEND_NOOPTION]
  470.                 );
  471.             return $err;
  472.         }
  473.  
  474.         if ($asString) {
  475.             $option = $directive->toArray(false);
  476.             $option = array_values($option);
  477.             $option = array_shift($option);
  478.         } else {
  479.             $option = $directive->toArray();
  480.         }
  481.         return $option;
  482.     }
  483.  
  484.     /**
  485.      * @return void
  486.      * @access public
  487.      * @since  0.1.0
  488.      */
  489.     function setOption($xpath, $value)
  490.     {
  491.         if (!is_array($xpath)) {
  492.             settype($xpath, 'array');
  493.         }
  494.  
  495.         $root =& $this->_conf->getRoot();
  496.         $directive =& $root->searchPath($xpath);
  497.  
  498.         if (!$directive) {
  499.             $option = implode('/', $xpath) ;
  500.             PEAR_ErrorStack::staticPush('@package_name@',
  501.                 PEAR_PACKAGEFILEMANAGER_FRONTEND_NOOPTION, 'warning',
  502.                 array('option' => $option),
  503.                 $GLOBALS['_PEAR_PACKAGEFILEMANAGER_FRONTEND_ERRORS'][PEAR_PACKAGEFILEMANAGER_FRONTEND_NOOPTION]
  504.                 );
  505.         }
  506.  
  507.         $directive->setContent($value);
  508.     }
  509.  
  510.     /**
  511.      * Returns whether or not errors have occurred (and been captured).
  512.      *
  513.      * @param  string   $level    Level name to check for a particular severity
  514.      * @return boolean
  515.      * @access public
  516.      * @since  0.1.0
  517.      */
  518.     function hasErrors($level = false)
  519.     {
  520.         return PEAR_ErrorStack::staticHasErrors('@package_name@', $level);
  521.     }
  522.  
  523.     /**
  524.      * Get a list of all errors since last purge
  525.      *
  526.      * @param  bool     $purge   set in order to empty the error stack
  527.      * @return array
  528.      * @access public
  529.      * @since  0.1.0
  530.      */
  531.     function getErrors($purge = false)
  532.     {
  533.         return PEAR_ErrorStack::staticGetErrors($purge);
  534.     }
  535.  
  536.     /**
  537.      * Repackage PEAR error
  538.      *
  539.      * @param  object  $error  PEAR_Error object to repackage
  540.      * @return void
  541.      * @access public
  542.      * @since  0.1.0
  543.      * @author Ian Eure <ieure@php.net>  from StackThunk 0.9.0
  544.      */
  545.     function repackagePEAR_Error(&$error)
  546.     {
  547.         static $map;
  548.         if (!isset($map)) {
  549.             $map = array(
  550.                 E_ERROR            => 'error',
  551.                 E_WARNING          => 'warning',
  552.                 E_PARSE            => 'exception',
  553.                 E_NOTICE           => 'notice',
  554.                 E_CORE_ERROR       => 'error',
  555.                 E_CORE_WARNING     => 'warning',
  556.                 E_COMPILE_ERROR    => 'exception',
  557.                 E_COMPILE_WARNING  => 'warning',
  558.                 E_USER_ERROR       => 'error',
  559.                 E_USER_WARNING     => 'warning',
  560.                 E_USER_NOTICE      => 'notice'
  561.             );
  562.         }
  563.  
  564.         // Strip this function from the trace
  565.         if (is_array($error->backtrace)) {
  566.             array_shift($error->backtrace);
  567.             $error->userinfo['backtrace'] =& $error->backtrace;
  568.         }
  569.         PEAR_ErrorStack::staticPush('@package_name@',
  570.             $error->code, $map[$error->level],
  571.             $error->userinfo, $error->message, false, $error->backtrace
  572.             );
  573.     }
  574.  
  575.     /**
  576.      * Log an error using PEAR::Log or compatible backend
  577.      *
  578.      * @param  string   $level    Error level
  579.      * @param  string   $message  Error message
  580.      * @return void
  581.      * @since  0.1.0
  582.      * @access public
  583.      */
  584.     function log($level, $message)
  585.     {
  586.         if ($this->_logger) {
  587.             if (method_exists($this->_logger, 'stringToPriority')) {
  588.                 $priority = $this->_logger->stringToPriority($level);
  589.             } else {
  590.                 $priority = null;
  591.             }
  592.             $this->_logger->log($message, $priority);
  593.         }
  594.     }
  595.  
  596.     /**
  597.      * Returns a reference to a session variable containing the form-page
  598.      * values and pages' validation status.
  599.      *
  600.      * @param  bool      If true, then reset the container: clear all default, constant and submitted values
  601.      * @return array
  602.      * @access public
  603.      * @since  0.1.0
  604.      */
  605.     function &container($reset = false)
  606.     {
  607.         $name = '_' . $this->driver . '_container';
  608.         if (!isset($_SESSION[$name]) || $reset) {
  609.             $_SESSION[$name] = array(
  610.                 'defaults'  => array(),
  611.                 'constants' => array(),
  612.                 'values'    => array(),
  613.                 'valid'     => array()
  614.             );
  615.         }
  616.         return $_SESSION[$name];
  617.     }
  618.  
  619.     /**
  620.      * Returns list of package maintainers
  621.      *
  622.      * @param  string  $users  maintainer category
  623.      * @return mixed   false on error or if maintainers does not exists, array otherwise
  624.      * @since  0.1.0
  625.      * @access public
  626.      */
  627.     function getMaintList($users = null)
  628.     {
  629.         $maint = array('lead','developer','contributor','helper');
  630.         if (isset($users) && !in_array($users, $maint)) {
  631.             PEAR_ErrorStack::staticPush('@package_name@',
  632.                 PEAR_PACKAGEFILEMANAGER_FRONTEND_WRONG_USERS, 'error',
  633.                 array('users' => $users),
  634.                 $GLOBALS['_PEAR_PACKAGEFILEMANAGER_FRONTEND_ERRORS'][PEAR_PACKAGEFILEMANAGER_FRONTEND_WRONG_USERS]
  635.                 );
  636.             return false;
  637.         }
  638.  
  639.         $sess =& $this->container();
  640.         if (!isset($sess['pfm'])) {
  641.             $this->_getPackage();
  642.         }
  643.  
  644.         if ($users == 'lead') {
  645.             $maintainers = $sess['pfm']->getLeads();
  646.         } elseif ($users == 'developer') {
  647.             $maintainers = $sess['pfm']->getDevelopers();
  648.         } elseif ($users == 'contributor') {
  649.             $maintainers = $sess['pfm']->getContributors();
  650.         } elseif ($users == 'helper') {
  651.             $maintainers = $sess['pfm']->getHelpers();
  652.         } else {
  653.             $maintainers = $sess['pfm']->getMaintainers();
  654.         }
  655.         return $maintainers;
  656.     }
  657.  
  658.     /**
  659.      * Wrapper for method PEAR_PackageFile_v2_rw::deleteMaintainer()
  660.      *
  661.      * @param  string  $handle  handle of user to remove from package
  662.      * @return TRUE on success, FALSE on error
  663.      * @since  0.2.0
  664.      * @access public
  665.      * @see    PEAR_PackageFile_v2_rw::deleteMaintainer()
  666.      */
  667.     function addMaintainer($role, $handle, $name, $email, $active = 'yes')
  668.     {
  669.         $sess =& $this->container();
  670.         if (!isset($sess['pfm'])) {
  671.             $this->_getPackage();
  672.         }
  673.         $ok = $sess['pfm']->addMaintainer($role, $handle, $name, $email, $active);
  674.         if (!$ok) {
  675.             PEAR_ErrorStack::staticPush('@package_name@',
  676.                 PEAR_PACKAGEFILEMANAGER_FRONTEND_WRONG_USEROLE, 'error',
  677.                 array('role' => $role, 'valid' => 'lead, developer, contributor, helper'),
  678.                 $GLOBALS['_PEAR_PACKAGEFILEMANAGER_FRONTEND_ERRORS'][PEAR_PACKAGEFILEMANAGER_FRONTEND_WRONG_USEROLE]
  679.                 );
  680.             return false;
  681.         }
  682.         return true;
  683.     }
  684.  
  685.     /**
  686.      * Wrapper for method PEAR_PackageFile_v2_rw::deleteMaintainer()
  687.      *
  688.      * @param  string  $handle  handle of user to remove from package
  689.      * @return TRUE on success, FALSE on error
  690.      * @since  0.2.0
  691.      * @access public
  692.      * @see    PEAR_PackageFile_v2_rw::deleteMaintainer()
  693.      */
  694.     function deleteMaintainer($handle)
  695.     {
  696.         $sess =& $this->container();
  697.         if (!isset($sess['pfm'])) {
  698.             $this->_getPackage();
  699.         }
  700.         $found = $sess['pfm']->deleteMaintainer($handle);
  701.         if (!$found) {
  702.             PEAR_ErrorStack::staticPush('@package_name@',
  703.                 PEAR_PACKAGEFILEMANAGER_FRONTEND_NOUSER, 'error',
  704.                 array('handle' => $handle),
  705.                 $GLOBALS['_PEAR_PACKAGEFILEMANAGER_FRONTEND_ERRORS'][PEAR_PACKAGEFILEMANAGER_FRONTEND_NOUSER]
  706.                 );
  707.         }
  708.         return $found;
  709.     }
  710.  
  711.     /**
  712.      * Prepare file list, with role, replacements and platform exception info.
  713.      *
  714.      * @param  boolean  $default  if we get initial data set at first run
  715.      * @param  boolean  $ignore   Either if you want all files or just ignored
  716.      * @param  string   $plugin   PEAR_PackageFileManager filelist generator
  717.      * @since  0.1.0
  718.      * @access public
  719.      */
  720.     function getFileList($default = false, $ignore = false, $plugin = 'file')
  721.     {
  722.         $sess =& $this->container();
  723.         if (!isset($sess['pfm'])) {
  724.             $this->_getPackage();
  725.         }
  726.         if (!isset($sess['files'])) {
  727.             $this->setFileList($plugin);
  728.         }
  729.         if ($default && isset($sess['defaults']['_files'])) {
  730.             $sess['files'] = $sess['defaults']['_files'];
  731.         }
  732.  
  733.         $list = array();
  734.  
  735.         foreach ($sess['files'] as $k => $file) {
  736.             if (!is_int($k)) {
  737.                 // global file mapping is not scanned
  738.                 continue;
  739.             }
  740.             if ($ignore === true && $file['ignore'] !== true) {
  741.                 continue;
  742.             } elseif ($ignore === false && $file['ignore'] === true) {
  743.                 continue;
  744.             }
  745.             // preserve original key ($k) to allow edit file
  746.             $list[$k] = $file;
  747.         }
  748.  
  749.         // returns files mapping with relative path to package directory
  750.         $pkg = $sess['pfm'];
  751.         $options = $pkg->getOptions();
  752.         $filelist = array();
  753.         foreach($list as $k => $file) {
  754.             $path = str_replace($options['packagedirectory'], '', $sess['files']['mapping'][$k]);
  755.             if (substr($path, 0, 1) == '/') {
  756.                 $path = substr($path, 1);
  757.             }
  758.             $filelist[$k] = $path;
  759.         }
  760.         $list['mapping'] = $filelist;
  761.  
  762.         $msg  = (count($list) - 1) .'/'. count($sess['files']) . ' ';
  763.         $msg .= ($ignore === true) ? 'ignored' : 'selected';
  764.         $msg .= ' file(s)';
  765.         $this->log('debug', str_pad(__FUNCTION__ .'('. __LINE__ .')', 20, '.') . $msg);
  766.  
  767.         return $list;
  768.     }
  769.  
  770.     /**
  771.      * Defines a listing of every file in package directory and
  772.      * all subdirectories.
  773.      *
  774.      * @param  string  $plugin   PEAR_PackageFileManager filelist generator
  775.      * @return void
  776.      * @since  0.1.0
  777.      * @access public
  778.      */
  779.     function setFileList($plugin = 'file')
  780.     {
  781.         $sess =& $this->container();
  782.         if (!isset($sess['pfm'])) {
  783.             $this->_getPackage();
  784.         }
  785.         $sess['files'] = array();
  786.  
  787.         $plugin = ucfirst(strtolower($plugin));
  788.         $pkg = $sess['pfm'];
  789.         $options = array_merge($pkg->getOptions(), array('filelistgenerator' => $plugin));
  790.         $pkg->setOptions($options, true);
  791.  
  792.         $generatorclass = 'PEAR_PackageFileManager_'. $plugin;
  793.         $this->log('debug', __FUNCTION__ .'('. __LINE__ .') generator plugin='.$generatorclass);
  794.         // get dir list corresponding to generator plugin
  795.         $gen = new $generatorclass($pkg, $options);
  796.         $fsMap = $gen->dirList(substr($options['packagedirectory'], 0, strlen($options['packagedirectory']) - 1));
  797.         $limit = count($fsMap);
  798.         $this->log('debug',
  799.             str_pad(__FUNCTION__ .'('. __LINE__ .')', 20, '.') .
  800.             ' ' . $limit . ' file(s) into tree "'. $options['packagedirectory']. '"'
  801.         );
  802.  
  803.         for ($i = 0; $i < $limit; $i++) {
  804.             $sess['files'][] = array('ignore' => false,
  805.                 'role' => '', 'platform' => false, 'replacements' => array()
  806.             );
  807.         }
  808.         $sess['files']['mapping'] = $fsMap;
  809.     }
  810.  
  811.     /**
  812.      * Returns list of package dependencies (other packages and/or extensions)
  813.      *
  814.      * @param  boolean $default  if we get initial data set at first run
  815.      * @return array
  816.      * @since  0.1.0
  817.      * @access public
  818.      */
  819.     function getDepList($default = false)
  820.     {
  821.         $sess =& $this->container();
  822.         if (!isset($sess['pfm'])) {
  823.             $this->_getPackage();
  824.         }
  825.         if (!isset($sess['dependencies'])) {
  826.             $this->_getDependencies();
  827.         }
  828.         if ($default && isset($sess['defaults']['_dependencies'])) {
  829.             $sess['dependencies'] = $sess['defaults']['_dependencies'];
  830.         }
  831.         return $sess['dependencies'];
  832.     }
  833.  
  834.     /**
  835.      * Returns list of directories and file extensions roles
  836.      *
  837.      * @param  boolean $default  if we get initial data set at first run
  838.      * @return array
  839.      * @since  0.1.0
  840.      * @access public
  841.      */
  842.     function getRoleList($default = false)
  843.     {
  844.         $sess =& $this->container();
  845.  
  846.         if (!isset($sess['roles'])) {
  847.             $filelist = $this->getFileList();
  848.             $sess['roles'] = array();
  849.             $settings_dir_roles = $this->getOption(array('settings', 'pfm', 'dir_roles'));
  850.             $settings_roles = $this->getOption(array('settings', 'pfm', 'roles'));
  851.             $ext_roles = array('*' => $settings_roles['*']);
  852.             $dir_roles = array();
  853.             $exts = array();
  854.             $dirs = array('.');
  855.  
  856.             foreach ($filelist['mapping'] as $k => $file) {
  857.                 $parts = pathinfo($file);
  858.  
  859.                 if (!in_array($parts['dirname'], $dirs)) {
  860.                     if (array_key_exists($parts['dirname'], $settings_dir_roles)) {
  861.                         $dir_roles[$parts['dirname']] = $settings_dir_roles[$parts['dirname']];
  862.                     } else {
  863.                         $dir_roles[$parts['dirname']] = 'php';
  864.                     }
  865.                     $dirs[] = $parts['dirname'];
  866.                 }
  867.                 if (isset($parts['extension']) && !in_array($parts['extension'], $exts)) {
  868.                     if (array_key_exists($parts['extension'], $settings_roles)) {
  869.                         $ext_roles[$parts['extension']] = $settings_roles[$parts['extension']];
  870.                     } else {
  871.                         $ext_roles[$parts['extension']] = $ext_roles['*'];
  872.                     }
  873.                     $exts[] = $parts['extension'];
  874.                 }
  875.             }
  876.  
  877.             foreach ($ext_roles as $ext => $role) {
  878.                 if ($ext !== '*') {
  879.                     $sess['roles'][] = array('directory' => '', 'extension' => $ext, 'role' => $role);
  880.                 }
  881.             }
  882.             foreach ($dir_roles as $dir => $role) {
  883.                 $sess['roles'][] = array('directory' => $dir, 'extension' => '', 'role' => $role);
  884.             }
  885.         }
  886.         // sort role list by extension (in ascending order), directories are always first
  887.         $roles = array();
  888.         foreach ($sess['roles'] as $key => $row) {
  889.             $roles[$key] = $row['extension'];
  890.         }
  891.         array_multisort($roles, SORT_ASC, $sess['roles']);
  892.  
  893.         if ($default && isset($sess['defaults']['_roles'])) {
  894.             $sess['roles'] = $sess['defaults']['_roles'];
  895.         }
  896.  
  897.         return $sess['roles'];
  898.     }
  899.  
  900.     /**
  901.      * Returns list of file role for specific files
  902.      *
  903.      * @return array
  904.      * @since  0.1.0
  905.      * @access public
  906.      */
  907.     function getExceptionList()
  908.     {
  909.         $sess =& $this->container();
  910.         $filelist = $this->getFileList();
  911.         return $filelist;
  912.     }
  913.  
  914.     /**
  915.      * Returns default values of a package (imported or pre-set)
  916.      *
  917.      * @param  string  $type   category of data
  918.      * @return array
  919.      * @since  0.1.0
  920.      * @access public
  921.      */
  922.     function getDefaults($type)
  923.     {
  924.         switch ($type) {
  925.             case 'package':
  926.                 $def = $this->_getPackage();
  927.                 break;
  928.             case 'release':
  929.                 $def = $this->_getRelease();
  930.                 break;
  931.             case 'maintainers':
  932.                 $def = $this->_getMaintainers();
  933.                 break;
  934.             case 'dependencies':
  935.                 $def = $this->_getDependencies();
  936.                 break;
  937.             case 'replacements':
  938.                 $def = $this->_getReplacements();
  939.                 break;
  940.             default:
  941.                 $def = null;
  942.         }
  943.         return $def;
  944.     }
  945.  
  946.     /**
  947.      * Sets default values used when we click on 'Reset' button of the frontend
  948.      *
  949.      * @param  string   $type          category of data
  950.      * @param  boolean  $overwrite     allow to define a new copy of default values
  951.      * @return void
  952.      * @since  0.2.0
  953.      * @access public
  954.      */
  955.     function setDefaults($type, $values = null, $overwrite = false)
  956.     {
  957.         $sess =& $this->container();
  958.  
  959.         if (isset($sess['defaults']["_$type"]) && !$overwrite) {
  960.             return;
  961.         }
  962.         switch ($type) {
  963.             case 'maintainers':
  964.             case 'dependencies':
  965.             case 'files':
  966.             case 'roles':
  967.                 if (!isset($values)) {
  968.                     $values = $sess[$type];
  969.                 }
  970.                 $sess['defaults']["_$type"] = $values;
  971.                 break;
  972.             default:
  973.                 break;
  974.         }
  975.     }
  976.  
  977.     /**
  978.      * Returns package summary informations:
  979.      * <pre>
  980.      *  - pearInstaller      : 'min', 'max', 'recommanded' and 'exclude' versions of PEAR installer
  981.      *  - phpVersion         : 'min', 'max' and 'exclude' versions of PHP dependency
  982.      *  - packageFileName    : the name of the packagefile, defaults to package.xml
  983.      *  - baseInstallDir     : the base directory to install this package in
  984.      *  - channel            :
  985.      *  - packageDir         : the path to the base directory of the package
  986.      *  - packageType        :
  987.      *  - packageName        :
  988.      *  - packageSummary     :
  989.      *  - packageDescription :
  990.      *  - packageOutputDir   : the path in which to place the generated package.xml
  991.      * </pre>
  992.      *
  993.      * @return array
  994.      * @since  0.1.0
  995.      * @access private
  996.      */
  997.     function _getPackage()
  998.     {
  999.         $packagedirectory  = realpathnix($this->packagedirectory);
  1000.         $pathtopackagefile = realpathnix($this->pathtopackagefile);
  1001.         $baseinstalldir = $this->getOption(array('settings', 'pfm', 'baseinstalldir'));
  1002.  
  1003.         if ($packagedirectory === false) {
  1004.             $optionsUpdate = array(
  1005.                 'pathtopackagefile' => $pathtopackagefile ? dirname($pathtopackagefile) : false,
  1006.                 'packagedirectory'  => realpathnix('.'),
  1007.                 'baseinstalldir'    => $baseinstalldir
  1008.             );
  1009.             if (is_file($pathtopackagefile)) {
  1010.                 $optionsUpdate['packagefile'] = basename($pathtopackagefile);
  1011.             }
  1012.             $newPackage = true;
  1013.         } else {
  1014.             $optionsUpdate = array(
  1015.                 'pathtopackagefile' => $pathtopackagefile ? dirname($pathtopackagefile) : false,
  1016.                 'packagedirectory'  => $packagedirectory,
  1017.                 'baseinstalldir'    => $baseinstalldir,
  1018.                 'clearcontents'     => false
  1019.             );
  1020.             if (is_file($packagedirectory)) {
  1021.                 $optionsUpdate['packagefile'] = basename($packagedirectory);
  1022.                 $optionsUpdate['packagedirectory'] = dirname($packagedirectory);
  1023.             }
  1024.             if (is_file($pathtopackagefile)) {
  1025.                 $packagefile = $pathtopackagefile;
  1026.             } else {
  1027.                 $packagefile  = ($pathtopackagefile) ? $pathtopackagefile : $packagedirectory;
  1028.                 if (substr($packagefile, -1, 1) == '/') {
  1029.                     $packagefile .= 'package.xml';
  1030.                 }
  1031.             }
  1032.             $pkg = &PEAR_PackageFileManager2::importFromPackageFile1($packagefile, $optionsUpdate);
  1033.             if (PEAR::isError($pkg)) {
  1034.                 $this->repackagePEAR_Error($pkg);
  1035.                 $newPackage = true;
  1036.             } else {
  1037.                 $newPackage = false;
  1038.             }
  1039.         }
  1040.  
  1041.         if ($newPackage) {
  1042.             $pkg = new PEAR_PackageFileManager2();
  1043.             $pkg->setOptions($optionsUpdate);
  1044.             $pkg->setPackageType('php');
  1045.             $pkg->setChannel('pear.php.net');
  1046.             $source = ' create';
  1047.             $packagefile = $optionsUpdate['packagedirectory'] . 'package.xml';
  1048.         } else {
  1049.             $source = ' import';
  1050.         }
  1051.         $pkg->setPearinstallerDep('1.4.3');
  1052.         $pkg->setPackageFile($packagefile);
  1053.         $source .= " package file '$packagefile'";
  1054.         $this->log('debug',
  1055.             str_pad(__FUNCTION__ .'('. __LINE__ .')', 20, '.') .
  1056.             $source);
  1057.  
  1058.         $sess =& $this->container();
  1059.         $sess['pfm'] =& $pkg;
  1060.         $sess['_newpackage'] = $newPackage;
  1061.         $options = $pkg->getOptions();
  1062.         $this->log('debug',
  1063.             str_pad(__FUNCTION__ .'('. __LINE__ .')', 20, '.') .
  1064.             ' PFM options='. serialize($options)
  1065.         );
  1066.  
  1067.         if ($sess['_newpackage']) {
  1068.             $def = array(
  1069.                 'pearInstaller'   => array('min' => '1.4.3', 'max' => false, 'recommanded' => false, 'exclude' => false),
  1070.                 'phpVersion'      => array('min' => '4.2.0', 'max' => false, 'exclude' => false),
  1071.                 'packageFileName' => $options['packagefile'],
  1072.                 'baseInstallDir'  => $options['baseinstalldir']
  1073.             );
  1074.         } else {
  1075.             $deps = $pkg->getDeps(true);
  1076.             if (is_array($deps['required']['php']['exclude'])) {
  1077.                 $deps['required']['php']['exclude'] = $deps['required']['php']['exclude'][0];
  1078.             }
  1079.             if (is_array($deps['required']['pearinstaller']['exclude'])) {
  1080.                 $deps['required']['pearinstaller']['exclude'] = $deps['required']['pearinstaller']['exclude'][0];
  1081.             }
  1082.             $def = array(
  1083.                 'phpVersion'      => $deps['required']['php'],
  1084.                 'pearInstaller'   => $deps['required']['pearinstaller'],
  1085.                 'packageFileName' => $options['packagefile'],
  1086.             );
  1087.  
  1088.         }
  1089.         $def = array_merge($def, array(
  1090.             'channel'            => $pkg->getChannel(),
  1091.             'packageDir'         => $options['packagedirectory'],
  1092.             'packageType'        => $pkg->getPackageType(),
  1093.             'packageName'        => $pkg->getPackage(),
  1094.             'packageSummary'     => $pkg->getSummary(),
  1095.             'packageDescription' => $pkg->getDescription(),
  1096.             'packageOutputDir'   => $this->getOption(array('settings', 'pfm', 'outputdirectory')),
  1097.             'baseInstallDir'     => $baseinstalldir
  1098.             ));
  1099.         return $def;
  1100.     }
  1101.  
  1102.     /**
  1103.      * Returns release notes informations:
  1104.      * <pre>
  1105.      *  - releaseState    :
  1106.      *  - releaseVersion  :
  1107.      *  - APIState        :
  1108.      *  - APIVersion      :
  1109.      *  - releaseDate     :
  1110.      *  - releaseLicense  :
  1111.      *  - releaseNotes    :
  1112.      * </pre>
  1113.      *
  1114.      * @return array
  1115.      * @since  0.1.0
  1116.      * @access private
  1117.      */
  1118.     function _getRelease()
  1119.     {
  1120.         $sess =& $this->container();
  1121.         $options = $sess['pfm']->getOptions();
  1122.  
  1123.         if ($sess['_newpackage']) {
  1124.             if (is_array($options['license'])) {
  1125.                 $license = $options['license'];
  1126.             } else {
  1127.                 $license = array('content' => $options['license']);
  1128.             }
  1129.             $def = array(
  1130.                 'releaseDate'    => time(),
  1131.                 'releaseLicense' => $license
  1132.             );
  1133.         } else {
  1134.             $uri = $sess['pfm']->getLicenseLocation();
  1135.             if ($uri) {
  1136.                 $uri = array_shift($uri);
  1137.             }
  1138.             $def = array(
  1139.                 'releaseState'   => $sess['pfm']->getState(),
  1140.                 'releaseVersion' => $sess['pfm']->getVersion(),
  1141.                 'APIState'       => $sess['pfm']->getState('api'),
  1142.                 'APIVersion'     => $sess['pfm']->getVersion('api'),
  1143.                 'releaseDate'    => $sess['pfm']->getDate(),
  1144.                 'releaseLicense' => array('content' => $sess['pfm']->getLicense(),
  1145.                                           'uri'     => $uri),
  1146.                 'releaseNotes'   => $sess['pfm']->getNotes()
  1147.             );
  1148.         }
  1149.         $this->log('debug',
  1150.             str_pad(__FUNCTION__ .'('. __LINE__ .')', 20, '.') .
  1151.             serialize($def)
  1152.         );
  1153.         return $def;
  1154.     }
  1155.  
  1156.     /**
  1157.      * Returns release informations:
  1158.      * <pre>
  1159.      *  - :
  1160.      * </pre>
  1161.      *
  1162.      * @return array
  1163.      * @since  0.1.0
  1164.      * @access private
  1165.      */
  1166.     function _getMaintainers()
  1167.     {
  1168.         $sess =& $this->container();
  1169.         $def = $sess['pfm']->getMaintainers();
  1170.         $this->log('debug',
  1171.             str_pad(__FUNCTION__ .'('. __LINE__ .')', 20, '.') .
  1172.             serialize($def)
  1173.         );
  1174.         return $def;
  1175.     }
  1176.  
  1177.     /**
  1178.      * Returns dependencies list, packages installed and php extensions available:
  1179.      * <pre>
  1180.      *  - :
  1181.      * </pre>
  1182.      *
  1183.      * @return array
  1184.      * @since  0.1.0
  1185.      * @access private
  1186.      */
  1187.     function _getDependencies()
  1188.     {
  1189.         $sess =& $this->container();
  1190.  
  1191.         $pearConfig = new PEAR_Config();
  1192.         $pear_install_dir = $pearConfig->get('php_dir');
  1193.         $pearRegistry = new PEAR_Registry($pear_install_dir);
  1194.  
  1195.         // PEAR packages installed from each channel
  1196.         $allpackages = $pearRegistry->_listAllPackages();
  1197.         foreach($allpackages as $channel => $packages) {
  1198.             if ($packages) {
  1199.                 sort($packages, SORT_ASC);
  1200.                 foreach ($packages as $package) {
  1201.                     $info = &$pearRegistry->getPackage($package, $channel);
  1202.                     if (is_object($info)) {
  1203.                         $name = $info->getPackage();
  1204.                     } else {
  1205.                         $name = $info['package'];
  1206.                     }
  1207.                     $sess['packages'][$channel][$name] = $name;
  1208.                 }
  1209.             } else {
  1210.                 $sess['packages'][$channel] = array();
  1211.             }
  1212.         }
  1213.  
  1214.         // PHP extensions available
  1215.         $sess['extensions'] = get_loaded_extensions();
  1216.  
  1217.         // Packages and Extensions dependencies
  1218.         $sess['dependencies'] = array();
  1219.         if ($sess['_newpackage'] === false) {
  1220.             $dependencies = $sess['pfm']->getDeps(true);
  1221.             foreach($dependencies as $dgroup => $dgroupval) {
  1222.                 foreach($dgroupval as $dtype => $deps) {
  1223.                     if ($dtype == 'php' || $dtype == 'pearinstaller') {
  1224.                         continue;
  1225.                     }
  1226.                     foreach($deps as $dependency) {
  1227.                         $dependency['type'] = $dgroup;
  1228.                         $dependency['name'] = $dependency['name'];
  1229.                         if (is_array($dependency['exclude'])) {
  1230.                             $dependency['exclude'] = $dependency['exclude'][0];
  1231.                         }
  1232.                         $sess['dependencies'][] = $dependency;
  1233.                     }
  1234.                 }
  1235.             }
  1236.         }
  1237.  
  1238.         $this->log('debug',
  1239.             str_pad(__FUNCTION__ .'('. __LINE__ .')', 20, '.') .
  1240.             ' dependencies=' . serialize($sess['dependencies'])
  1241.         );
  1242.         $this->log('debug',
  1243.             str_pad(__FUNCTION__ .'('. __LINE__ .')', 20, '.') .
  1244.             ' packages=' . serialize($sess['packages'])
  1245.         );
  1246.         $this->log('debug',
  1247.             str_pad(__FUNCTION__ .'('. __LINE__ .')', 20, '.') .
  1248.             ' extensions=' . serialize($sess['extensions'])
  1249.         );
  1250.         $def = array($sess['dependencies'], $sess['packages'], $sess['extensions']);
  1251.         return $def;
  1252.     }
  1253.  
  1254.     /**
  1255.      * Returns replaces tasks applied on each file of the distribution:
  1256.      * <pre>
  1257.      *  - :
  1258.      * </pre>
  1259.      *
  1260.      * @return array
  1261.      * @since  0.1.0
  1262.      * @access private
  1263.      */
  1264.     function _getReplacements()
  1265.     {
  1266.         $sess =& $this->container();
  1267.         $option = $sess['pfm']->getOptions();
  1268.  
  1269.         $filelist = $sess['pfm']->getFilelist(true);
  1270.         if (is_array($filelist)) {
  1271.             $sess['roles'] = array();
  1272.             $dirs = array('.');
  1273.             $exts = array();
  1274.             $k = 0;
  1275.             foreach($filelist as $fname => $contents) {
  1276.                 $sess['files']['mapping'][$k] = $option['packagedirectory'] . $fname;
  1277.                 $parts = pathinfo($contents['attribs']['name']);
  1278.                 if (!in_array($parts['dirname'], $dirs)) {
  1279.                     $dirs[] = $parts['dirname'];
  1280.                     $dir_roles = $this->getOption(array('settings', 'pfm', 'dir_roles'));
  1281.                     if (array_key_exists($parts['dirname'], $dir_roles)) {
  1282.                         $role = $dir_roles[$parts['dirname']];
  1283.                     } else {
  1284.                         $role = 'php';
  1285.                     }
  1286.                     $sess['roles'][] = array('directory' => $parts['dirname'], 'extension' => '', 'role' => $role);
  1287.                 }
  1288.                 if (isset($parts['extension']) && !in_array($parts['extension'], $exts)) {
  1289.                     $exts[] = $parts['extension'];
  1290.                     $sess['roles'][] = array('directory' => '', 'extension' => $parts['extension'],
  1291.                         'role' => $contents['attribs']['role']
  1292.                     );
  1293.                 }
  1294.                 $role = isset($parts['extension']) ? '' : $contents['attribs']['role'];
  1295.                 $sess['files'][$k] = array('ignore' => false,
  1296.                     'role' => $role, 'platform' => false, 'replacements' => array()
  1297.                 );
  1298.                 if (isset($contents['tasks:replace'])) {
  1299.                     if (count($contents['tasks:replace']) == 1) {
  1300.                         $contents['tasks:replace'] = array($contents['tasks:replace']);
  1301.                     }
  1302.                     foreach($contents['tasks:replace'] as $r => $replace) {
  1303.                         $sess['files'][$k]['replacements'][$r] = array(
  1304.                             'from' => $replace['attribs']['from'],
  1305.                             'type' => $replace['attribs']['type'],
  1306.                             'to'   => $replace['attribs']['to']
  1307.                         );
  1308.                     }
  1309.                 }
  1310.                 $k++;
  1311.             }
  1312.         }
  1313.  
  1314.         return $sess['files'];
  1315.     }
  1316.  
  1317.     /**
  1318.      * Returns the element's value
  1319.      *
  1320.      * @param  string   $pageName      name of the page
  1321.      * @param  string   $elementName   name of the element in the page
  1322.      * @return mixed    value for the element
  1323.      * @since  0.2.0
  1324.      * @access public
  1325.      */
  1326.     function exportValue($pageName, $elementName)
  1327.     {
  1328.         $sess =& $this->container();
  1329.         return isset($sess['values'][$pageName][$elementName])? $sess['values'][$pageName][$elementName]: null;
  1330.     }
  1331.  
  1332.     /**
  1333.      *
  1334.      * @param  string  $pageId  page identifier
  1335.      * @return string
  1336.      * @since  0.2.0
  1337.      * @access public
  1338.      */
  1339.     function getPageName($pageId)
  1340.     {
  1341.         $pagePath = array('settings', 'gui', 'pages', array('page', array('id' => $pageId)));
  1342.         $page = $this->getOption($pagePath, false);
  1343.         return $page['page']['@']['name'];
  1344.     }
  1345.  
  1346.     /**
  1347.      *
  1348.      * @since  0.1.0
  1349.      * @access public
  1350.      * @return mixed
  1351.      */
  1352.     function preparePackageFile()
  1353.     {
  1354.         $sess =& $this->container();
  1355.         $pkg = $sess['pfm'];
  1356.  
  1357.         // get valid options from page 1
  1358.         $pageName = $this->getPageName('page1');
  1359.         $options = array_merge($pkg->getOptions(), array(
  1360.             'outputdirectory'  => $this->exportValue($pageName,'packageOutputDir'),
  1361.             'packagefile'      => $this->exportValue($pageName,'packageFileName'),
  1362.             'packagedirectory' => $this->exportValue($pageName,'packageDir'),
  1363.             'baseinstalldir'   => $this->exportValue($pageName,'baseInstallDir')
  1364.         ));
  1365.         $warn = $pkg->setOptions($options, true);
  1366.         $this->pushWarning($warn);
  1367.  
  1368.         $pearInstaller = $this->exportValue($pageName,'pearInstaller');
  1369.         if (empty($pearInstaller['min'])) {
  1370.             $installer['min'] = false;
  1371.         } else {
  1372.             $installer['min'] = $pearInstaller['min'];
  1373.         }
  1374.         if (empty($pearInstaller['max'])) {
  1375.             $installer['max'] = false;
  1376.         } else {
  1377.             $installer['max'] = $pearInstaller['max'];
  1378.         }
  1379.         if (empty($pearInstaller['recommended'])) {
  1380.             $installer['recommended'] = false;
  1381.         } else {
  1382.             $installer['recommended'] = $pearInstaller['recommended'];
  1383.         }
  1384.         if (empty($pearInstaller['exclude'])) {
  1385.             $installer['exclude'] = false;
  1386.         } else {
  1387.             $installer['exclude'] = $pearInstaller['exclude'];
  1388.         }
  1389.  
  1390.         $phpVersion = $this->exportValue($pageName,'phpVersion');
  1391.         if (empty($phpVersion['min'])) {
  1392.             $php['min'] = false;
  1393.         } else {
  1394.             $php['min'] = $phpVersion['min'];
  1395.         }
  1396.         if (empty($phpVersion['max'])) {
  1397.             $php['max'] = false;
  1398.         } else {
  1399.             $php['max'] = $phpVersion['max'];
  1400.         }
  1401.         if (empty($phpVersion['exclude'])) {
  1402.             $php['exclude'] = false;
  1403.         } else {
  1404.             $php['exclude'] = $phpVersion['exclude'];
  1405.         }
  1406.  
  1407.         $packagetype = $this->exportValue($pageName,'packageType');
  1408.         $channel     = $this->exportValue($pageName,'channel');
  1409.         $package     = $this->exportValue($pageName,'packageName');
  1410.         $summary     = $this->exportValue($pageName,'packageSummary');
  1411.         $descr       = $this->exportValue($pageName,'packageDescription');
  1412.  
  1413.         $pkg->clearDeps();
  1414.         $pkg->clearContents();
  1415.         $pkg->setPearinstallerDep($installer['min'], $installer['max'], $installer['recommended'], $installer['exclude']);
  1416.         $pkg->setPhpDep($php['min'], $php['max'], $php['exclude']);
  1417.         $pkg->setChannel($channel);
  1418.         $pkg->setPackage($package);
  1419.         $pkg->setPackageType($packagetype);
  1420.         $pkg->setSummary($summary);
  1421.         $pkg->setDescription($descr);
  1422.  
  1423.         // get valid options from page 2
  1424.         $pageName = $this->getPageName('page2');
  1425.         $license  = $this->exportValue($pageName,'releaseLicense');
  1426.         if (empty($license['uri'])) {
  1427.             $uri = false;
  1428.         } else {
  1429.             $uri = $license['uri'];
  1430.         }
  1431.         $releaseState   = $this->exportValue($pageName,'releaseState');
  1432.         $releaseVersion = $this->exportValue($pageName,'releaseVersion');
  1433.         $apiState       = $this->exportValue($pageName,'APIState');
  1434.         $apiVersion     = $this->exportValue($pageName,'APIVersion');
  1435.         $releaseNotes   = $this->exportValue($pageName,'releaseNotes');
  1436.  
  1437.         $pkg->setLicense($license['content'], $uri);
  1438.         $pkg->addRelease();
  1439.         $pkg->setAPIVersion($apiVersion);
  1440.         $pkg->setAPIStability($apiState);
  1441.         $pkg->setReleaseVersion($releaseVersion);
  1442.         $pkg->setReleaseStability($releaseState);
  1443.         $pkg->setNotes($releaseNotes);
  1444.  
  1445.         // get valid options from page 4
  1446.         if (isset($sess['dependencies'])) {
  1447.             foreach ($sess['dependencies'] as $dependency) {
  1448.                 extract($dependency);
  1449.                 if (empty($extension)) {
  1450.                     $pkg->addPackageDepWithChannel($type, $name, $channel, $min, $max, $recommended, $exclude);
  1451.                 } else {
  1452.                     $pkg->addExtensionDep($type, $extension, $min, $max, $recommended, $exclude);
  1453.                 }
  1454.             }
  1455.         }
  1456.  
  1457.         // get valid options from page 5
  1458.         $pageName = $this->getPageName('page5');
  1459.         $plugin = $this->exportValue($pageName,'filelistgenerator');
  1460.         if (isset($plugin)) {
  1461.             $options = array_merge($pkg->getOptions(), array(
  1462.                 'filelistgenerator' => $plugin
  1463.             ));
  1464.             $warn = $pkg->setOptions($options, true);
  1465.             $this->pushWarning($warn);
  1466.         }
  1467.  
  1468.         if (isset($sess['files'])) {
  1469.             foreach ($sess['files'] as $k => $file) {
  1470.                 if (!is_int($k)) {
  1471.                     // global file mapping is not scanned
  1472.                     continue;
  1473.                 }
  1474.                 if ($file['ignore'] === true) {
  1475.                     $pkg->addIgnore($sess['files']['mapping'][$k]);
  1476.                 }
  1477.                 foreach($file['replacements'] as $r => $replace) {
  1478.                     $f = str_replace($options['packagedirectory'], '', $sess['files']['mapping'][$k]);
  1479.                     $warn = $pkg->addReplacement($f,
  1480.                         $replace['type'], $replace['from'], $replace['to']);
  1481.                     $this->pushWarning($warn);
  1482.                 }
  1483.             }
  1484.         }
  1485.  
  1486.         // get valid options from page 6
  1487.         $pageName = $this->getPageName('page6');
  1488.         if (isset($sess['roles'])) {
  1489.             // recreate roles mapping (extensions and directories)
  1490.             $dir_roles = $ext_roles = array();
  1491.             foreach ($sess['roles'] as $k => $role) {
  1492.                 if (empty($role['extension'])) {
  1493.                     $dir_roles[$role['dirname']] = $role['role'];
  1494.                 } else {
  1495.                     $ext_roles[$role['extension']] = $role['role'];
  1496.                 }
  1497.             }
  1498.             $options = array_merge($pkg->getOptions(), array(
  1499.                 'dir_roles' => $dir_roles, 'roles' => $ext_roles
  1500.             ));
  1501.             $warn = $pkg->setOptions($options, true);
  1502.             $this->pushWarning($warn);
  1503.         }
  1504.  
  1505.         // get valid options from page 7
  1506.         $pageName = $this->getPageName('page7');
  1507.         if (isset($sess['files'])) {
  1508.             $exceptions = array();
  1509.             foreach ($sess['files'] as $k => $file) {
  1510.                 if (!is_int($k)) {
  1511.                     // global file mapping is not scanned
  1512.                     continue;
  1513.                 }
  1514.                 if (empty($file['role'])) {
  1515.                     continue;
  1516.                 }
  1517.                 $f = str_replace($options['packagedirectory'], '', $sess['files']['mapping'][$k]);
  1518.                 $exceptions[$f] = $file['role'];
  1519.             }
  1520.             $options = array_merge($pkg->getOptions(), array(
  1521.                 'exceptions' => $exceptions
  1522.             ));
  1523.             $warn = $pkg->setOptions($options, true);
  1524.             $this->pushWarning($warn);
  1525.         }
  1526.  
  1527.         // get valid options from page 8
  1528.         $pageName = $this->getPageName('page8');
  1529.         $options = array_merge($pkg->getOptions(), array(
  1530.             'changelogoldtonew' => $this->exportValue($pageName,'changelogOldToNew'),
  1531.             'simpleoutput'      => $this->exportValue($pageName,'simpleOutput')
  1532.         ));
  1533.         $warn = $pkg->setOptions($options, true);
  1534.         $this->pushWarning($warn);
  1535.  
  1536.         return $pkg;
  1537.     }
  1538.  
  1539.     /**
  1540.      *
  1541.      * @since  0.1.0
  1542.      * @access public
  1543.      * @return mixed
  1544.      */
  1545.     function buildPackageFile($debug, $exportV1, $changelogOldToNew, $simpleOutput)
  1546.     {
  1547.         $pkg = $this->preparePackageFile();
  1548.  
  1549.         $options = array_merge($pkg->getOptions(), array(
  1550.             'changelogoldtonew' => $changelogOldToNew,
  1551.             'simpleoutput'      => $simpleOutput,
  1552.         ));
  1553.         $pkg->setOptions($options, true);
  1554.  
  1555.         $pkg->generateContents();
  1556.         // purge warnings
  1557.         $warn = $pkg->getValidationWarnings();
  1558.  
  1559.         if (isset($debug) && $debug) {
  1560.             ob_start();
  1561.             $warn = $pkg->writePackageFile($debug);
  1562.             $preview = ob_get_contents();
  1563.             ob_end_clean();
  1564.         } else {
  1565.             if ($exportV1) {
  1566.                 $pkgV1 = &$pkg->exportCompatiblePackageFile1();
  1567.                 $this->pushWarning($pkgV1);
  1568.                 $warn = $pkgV1->writePackageFile($debug);
  1569.                 $this->pushWarning($warn);
  1570.             }
  1571.             $warn = $pkg->writePackageFile($debug);
  1572.         }
  1573.         $this->pushWarning($warn);
  1574.  
  1575.         if (PEAR_PackageFileManager_Frontend::hasErrors()) {
  1576.             return false;
  1577.         }
  1578.  
  1579.         if (isset($debug) && $debug) {
  1580.             return $preview;
  1581.         }
  1582.         //$options = $pkg->getOptions();
  1583.         $outputdir = !empty($options['outputdirectory']) ? $options['outputdirectory'] : $options['packagedirectory'];
  1584.         $packagexml = $outputdir . $options['packagefile'];
  1585.         return $packagexml;
  1586.     }
  1587.  
  1588.     /**
  1589.      * Push a warning or error to the warning stack.
  1590.      *
  1591.      * @param  object  $err  PEAR_Error instance
  1592.      * @return void
  1593.      * @since  0.1.0
  1594.      * @access public
  1595.      */
  1596.     function pushWarning($err)
  1597.     {
  1598.         if (PEAR::isError($err)) {
  1599.             $this->repackagePEAR_Error($err);
  1600.         }
  1601.     }
  1602.  
  1603.    /**
  1604.     * Processes the request.
  1605.     *
  1606.     * @access  public
  1607.     * @since   0.1.0
  1608.     * @abstract
  1609.     */
  1610.     function run()
  1611.     {
  1612.         trigger_error('run is an abstract method that must be ' .
  1613.                       'overridden in the child class', E_USER_ERROR);
  1614.     }
  1615. }
  1616. ?>