[ Index ]
 

Code source de PHP PEAR 1.4.5

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/PEAR/ -> PackageFileManager.php (source)

   1  <?php
   2  //
   3  // +------------------------------------------------------------------------+
   4  // | PEAR :: Package File Manager                                           |
   5  // +------------------------------------------------------------------------+
   6  // | Copyright (c) 2003-2004 Gregory Beaver                                 |
   7  // | Email         cellog@phpdoc.org                                        |
   8  // +------------------------------------------------------------------------+
   9  // | This source file is subject to version 3.00 of the PHP License,        |
  10  // | that is available at http://www.php.net/license/3_0.txt.               |
  11  // | If you did not receive a copy of the PHP license and are unable to     |
  12  // | obtain it through the world-wide-web, please send a note to            |
  13  // | license@php.net so we can mail you a copy immediately.                 |
  14  // +------------------------------------------------------------------------+
  15  // | Portions of this code based on phpDocumentor                           |
  16  // | Web           http://www.phpdoc.org                                    |
  17  // | Mirror        http://phpdocu.sourceforge.net/                          |
  18  // +------------------------------------------------------------------------+
  19  // $Id: PackageFileManager.php,v 1.42 2005/04/06 22:21:20 cellog Exp $
  20  //
  21  
  22  /**
  23   * @package PEAR_PackageFileManager
  24   */
  25  /**
  26   * PEAR installer
  27   */
  28  require_once  'PEAR/Common.php';
  29  /**#@+
  30   * Error Codes
  31   */
  32  define('PEAR_PACKAGEFILEMANAGER_NOSTATE', 1);
  33  define('PEAR_PACKAGEFILEMANAGER_NOVERSION', 2);
  34  define('PEAR_PACKAGEFILEMANAGER_NOPKGDIR', 3);
  35  define('PEAR_PACKAGEFILEMANAGER_NOBASEDIR', 4);
  36  define('PEAR_PACKAGEFILEMANAGER_GENERATOR_NOTFOUND', 5);
  37  define('PEAR_PACKAGEFILEMANAGER_GENERATOR_NOTFOUND_ANYWHERE', 6);
  38  define('PEAR_PACKAGEFILEMANAGER_CANTWRITE_PKGFILE', 7);
  39  define('PEAR_PACKAGEFILEMANAGER_DEST_UNWRITABLE', 8);
  40  define('PEAR_PACKAGEFILEMANAGER_CANTCOPY_PKGFILE', 9);
  41  define('PEAR_PACKAGEFILEMANAGER_CANTOPEN_TMPPKGFILE', 10);
  42  define('PEAR_PACKAGEFILEMANAGER_PATH_DOESNT_EXIST', 11);
  43  define('PEAR_PACKAGEFILEMANAGER_NOCVSENTRIES', 12);
  44  define('PEAR_PACKAGEFILEMANAGER_DIR_DOESNT_EXIST', 13);
  45  define('PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS', 14);
  46  define('PEAR_PACKAGEFILEMANAGER_NOPACKAGE', 15);
  47  define('PEAR_PACKAGEFILEMANAGER_WRONG_MROLE', 16);
  48  define('PEAR_PACKAGEFILEMANAGER_NOSUMMARY', 17);
  49  define('PEAR_PACKAGEFILEMANAGER_NODESC', 18);
  50  define('PEAR_PACKAGEFILEMANAGER_ADD_MAINTAINERS', 19);
  51  define('PEAR_PACKAGEFILEMANAGER_NO_FILES', 20);
  52  define('PEAR_PACKAGEFILEMANAGER_IGNORED_EVERYTHING', 21);
  53  define('PEAR_PACKAGEFILEMANAGER_INVALID_PACKAGE', 22);
  54  define('PEAR_PACKAGEFILEMANAGER_INVALID_REPLACETYPE', 23);
  55  define('PEAR_PACKAGEFILEMANAGER_INVALID_ROLE', 24);
  56  define('PEAR_PACKAGEFILEMANAGER_PHP_NOT_PACKAGE', 25);
  57  define('PEAR_PACKAGEFILEMANAGER_CVS_PACKAGED', 26);
  58  define('PEAR_PACKAGEFILEMANAGER_NO_PHPCOMPATINFO', 27);
  59  /**#@-*/
  60  /**
  61   * Error messages
  62   * @global array $GLOBALS['_PEAR_PACKAGEFILEMANAGER_ERRORS']
  63   */
  64  $GLOBALS['_PEAR_PACKAGEFILEMANAGER_ERRORS'] =
  65  array(
  66      'en' =>
  67      array(
  68          PEAR_PACKAGEFILEMANAGER_NOSTATE =>
  69              'Release State (option \'state\') must by specified in PEAR_PackageFileManager setOptions (alpha|beta|stable)',
  70          PEAR_PACKAGEFILEMANAGER_NOVERSION =>
  71              'Release Version (option \'version\') must be specified in PEAR_PackageFileManager setOptions',
  72          PEAR_PACKAGEFILEMANAGER_NOPKGDIR =>
  73              'Package source base directory (option \'packagedirectory\') must be ' .
  74              'specified in PEAR_PackageFileManager setOptions',
  75          PEAR_PACKAGEFILEMANAGER_NOBASEDIR =>
  76              'Package install base directory (option \'baseinstalldir\') must be ' .
  77              'specified in PEAR_PackageFileManager setOptions',
  78          PEAR_PACKAGEFILEMANAGER_GENERATOR_NOTFOUND =>
  79              'Base class "%s" can\'t be located',
  80          PEAR_PACKAGEFILEMANAGER_GENERATOR_NOTFOUND_ANYWHERE =>
  81              'Base class "%s" can\'t be located in default or user-specified directories',
  82          PEAR_PACKAGEFILEMANAGER_CANTWRITE_PKGFILE =>
  83              'Failed to write package.xml file to destination directory',
  84          PEAR_PACKAGEFILEMANAGER_DEST_UNWRITABLE =>
  85              'Destination directory "%s" is unwritable',
  86          PEAR_PACKAGEFILEMANAGER_CANTCOPY_PKGFILE =>
  87              'Failed to copy package.xml.tmp file to package.xml',
  88          PEAR_PACKAGEFILEMANAGER_CANTOPEN_TMPPKGFILE =>
  89              'Failed to open temporary file "%s" for writing',
  90          PEAR_PACKAGEFILEMANAGER_PATH_DOESNT_EXIST =>
  91              'package.xml file path "%s" doesn\'t exist or isn\'t a directory',
  92          PEAR_PACKAGEFILEMANAGER_NOCVSENTRIES =>
  93              'Directory "%s" is not a CVS directory (it must have the CVS/Entries file)',
  94          PEAR_PACKAGEFILEMANAGER_DIR_DOESNT_EXIST =>
  95              'Package source base directory "%s" doesn\'t exist or isn\'t a directory',
  96          PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS =>
  97              'Run $managerclass->setOptions() before any other methods',
  98          PEAR_PACKAGEFILEMANAGER_NOPACKAGE =>
  99              'Package Name (option \'package\') must by specified in PEAR_PackageFileManager '.
 100              'setOptions to create a new package.xml',
 101          PEAR_PACKAGEFILEMANAGER_NOSUMMARY =>
 102              'Package Summary (option \'summary\') must by specified in PEAR_PackageFileManager' .
 103              ' setOptions to create a new package.xml',
 104          PEAR_PACKAGEFILEMANAGER_NODESC =>
 105              'Detailed Package Description (option \'description\') must be' .
 106              ' specified in PEAR_PackageFileManager setOptions to create a new package.xml',
 107          PEAR_PACKAGEFILEMANAGER_WRONG_MROLE =>
 108              'Maintainer role must be one of "%s", was "%s"',
 109          PEAR_PACKAGEFILEMANAGER_ADD_MAINTAINERS =>
 110              'Add maintainers to a package before generating the package.xml',
 111          PEAR_PACKAGEFILEMANAGER_NO_FILES =>
 112              'No files found, check the path "%s"',
 113          PEAR_PACKAGEFILEMANAGER_IGNORED_EVERYTHING =>
 114              'No files left, check the path "%s" and ignore option "%s"',
 115          PEAR_PACKAGEFILEMANAGER_INVALID_PACKAGE =>
 116              'Package validation failed:%s%s',
 117          PEAR_PACKAGEFILEMANAGER_INVALID_REPLACETYPE =>
 118              'Replacement Type must be one of "%s", was passed "%s"',
 119          PEAR_PACKAGEFILEMANAGER_INVALID_ROLE =>
 120              'Invalid file role passed to addRole, must be one of "%s", was passed "%s"',
 121          PEAR_PACKAGEFILEMANAGER_PHP_NOT_PACKAGE =>
 122              'addDependency had PHP as a package, use type="php"',
 123          PEAR_PACKAGEFILEMANAGER_CVS_PACKAGED =>
 124              'path "%path%" contains CVS directory',
 125          PEAR_PACKAGEFILEMANAGER_NO_PHPCOMPATINFO =>
 126              'PHP_Compat is not installed, cannot detect dependencies',
 127          ),
 128          // other language translations go here
 129       );
 130  /**
 131   * PEAR :: PackageFileManager updates the <filelist></filelist> section
 132   * of a PEAR package.xml file to reflect the current files in
 133   * preparation for a release.
 134   *
 135   * The PEAR_PackageFileManager class uses a plugin system to generate the
 136   * list of files in a package.  This allows both standard recursive
 137   * directory parsing (plugin type file) and more intelligent options
 138   * such as the CVS browser {@link PEAR_PackageFileManager_Cvs}, which
 139   * grabs all files in a local CVS checkout to create the list, ignoring
 140   * any other local files.
 141   *
 142   * Other options include specifying roles for file extensions (all .php
 143   * files are role="php", for example), roles for directories (all directories
 144   * named "tests" are given role="tests" by default), and exceptions.
 145   * Exceptions are specific pathnames with * and ? wildcards that match
 146   * a default role, but should have another.  For example, perhaps
 147   * a debug.tpl template would normally be data, but should be included
 148   * in the docs role.  Along these lines, to exclude files entirely,
 149   * use the ignore option.
 150   *
 151   * Required options for a release include version, baseinstalldir, state,
 152   * and packagedirectory (the full path to the local location of the
 153   * package to create a package.xml file for)
 154   *
 155   * Example usage:
 156   * <code>
 157   * <?php
 158   * require_once('PEAR/PackageFileManager.php');
 159   * $packagexml = new PEAR_PackageFileManager;
 160   * $e = $packagexml->setOptions(
 161   * array('baseinstalldir' => 'PhpDocumentor',
 162   *  'version' => '1.2.1',
 163   *  'packagedirectory' => 'C:/Web Pages/chiara/phpdoc2/',
 164   *  'state' => 'stable',
 165   *  'filelistgenerator' => 'cvs', // generate from cvs, use file for directory
 166   *  'notes' => 'We\'ve implemented many new and exciting features',
 167   *  'ignore' => array('TODO', 'tests/'), // ignore TODO, all files in tests/
 168   *  'installexceptions' => array('phpdoc' => '/*'), // baseinstalldir ="/" for phpdoc
 169   *  'dir_roles' => array('tutorials' => 'doc'),
 170   *  'exceptions' => array('README' => 'doc', // README would be data, now is doc
 171   *                        'PHPLICENSE.txt' => 'doc'))); // same for the license
 172   * if (PEAR::isError($e)) {
 173   *     echo $e->getMessage();
 174   *     die();
 175   * }
 176   * $e = $test->addPlatformException('pear-phpdoc.bat', 'windows');
 177   * if (PEAR::isError($e)) {
 178   *     echo $e->getMessage();
 179   *     exit;
 180   * }
 181   * $packagexml->addRole('pkg', 'doc'); // add a new role mapping
 182   * if (PEAR::isError($e)) {
 183   *     echo $e->getMessage();
 184   *     exit;
 185   * }
 186   * // replace @PHP-BIN@ in this file with the path to php executable!  pretty neat
 187   * $e = $test->addReplacement('pear-phpdoc', 'pear-config', '@PHP-BIN@', 'php_bin');
 188   * if (PEAR::isError($e)) {
 189   *     echo $e->getMessage();
 190   *     exit;
 191   * }
 192   * $e = $test->addReplacement('pear-phpdoc.bat', 'pear-config', '@PHP-BIN@', 'php_bin');
 193   * if (PEAR::isError($e)) {
 194   *     echo $e->getMessage();
 195   *     exit;
 196   * }
 197   * // note use of {@link debugPackageFile()} - this is VERY important
 198   * if (isset($_GET['make']) || (isset($_SERVER['argv'][2]) &&
 199   *       $_SERVER['argv'][2] == 'make')) {
 200   *     $e = $packagexml->writePackageFile();
 201   * } else {
 202   *     $e = $packagexml->debugPackageFile();
 203   * }
 204   * if (PEAR::isError($e)) {
 205   *     echo $e->getMessage();
 206   *     die();
 207   * }
 208   * ?>
 209   * </code>
 210   * 
 211   * In addition, a package.xml file can now be generated from
 212   * scratch, with the usage of new options package, summary, description, and
 213   * the use of the {@link addMaintainer()} method
 214   * @package PEAR_PackageFileManager
 215   */
 216  class PEAR_PackageFileManager
 217  {
 218      /**
 219       * Format: array(array(regexp-ready string to search for whole path,
 220       * regexp-ready string to search for basename of ignore strings),...)
 221       * @var false|array
 222       * @access private
 223       */
 224      var $_ignore = false;
 225      
 226      /**
 227       * Contents of the package.xml file
 228       * @var string
 229       * @access private
 230       */
 231      var $_packageXml = false;
 232      
 233      /**
 234       * Contents of the original package.xml file, if any
 235       * @var string
 236       * @access private
 237       */
 238      var $_oldPackageXml = false;
 239      
 240      /**
 241       * @access private
 242       * @var PEAR_Common
 243       */
 244      var $_pear;
 245      
 246      /**
 247       * @access private
 248       * @var array
 249       */
 250      var $_warningStack = array();
 251  
 252      /**
 253       * flag used to determine whether to use PHP_CompatInfo to detect deps
 254       * @var boolean
 255       * @access private
 256       */
 257      var $_detectDependencies = false;
 258      
 259      /**
 260       * @access private
 261       * @var string
 262       */
 263      var $_options = array(
 264                        'packagefile' => 'package.xml',
 265                        'doctype' => 'http://pear.php.net/dtd/package-1.0',
 266                        'filelistgenerator' => 'file',
 267                        'license' => 'PHP License',
 268                        'changelogoldtonew' => true,
 269                        'roles' =>
 270                          array(
 271                              'php' => 'php',
 272                              'html' => 'doc',
 273                              '*' => 'data',
 274                               ),
 275                        'dir_roles' =>
 276                          array(
 277                              'docs' => 'doc',
 278                              'examples' => 'doc',
 279                              'tests' => 'test',
 280                               ),
 281                        'exceptions' => array(),
 282                        'installexceptions' => array(),
 283                        'installas' => array(),
 284                        'platformexceptions' => array(),
 285                        'scriptphaseexceptions' => array(),
 286                        'ignore' => array(),
 287                        'include' => false,
 288                        'deps' => false,
 289                        'maintainers' => false,
 290                        'notes' => '',
 291                        'changelognotes' => false,
 292                        'outputdirectory' => false,
 293                        'pathtopackagefile' => false,
 294                        'lang' => 'en',
 295                        'configure_options' => array(),
 296                        'replacements' => array(),
 297                        'pearcommonclass' => false,
 298                        'simpleoutput' => false,
 299                        'addhiddenfiles' => false,
 300                        'cleardependencies' => false,
 301                        );
 302      
 303      /**
 304       * Does nothing, use setOptions
 305       *
 306       * The constructor is not used in order to be able to
 307       * return a PEAR_Error from setOptions
 308       * @see setOptions()
 309       */
 310      function PEAR_PackageFileManager()
 311      {
 312      }
 313      
 314      /**
 315       * Set package.xml generation options
 316       *
 317       * The options array is indexed as follows:
 318       * <code>
 319       * $options = array('option_name' => <optionvalue>);
 320       * </code>
 321       *
 322       * The documentation below simplifies this description through
 323       * the use of option_name without quotes
 324       *
 325       * Configuration options:
 326       * - lang: lang controls the language in which error messages are
 327       *         displayed.  There are currently only English error messages,
 328       *         but any contributed will be added over time.<br>
 329       *         Possible values: en (default)
 330       * - packagefile: the name of the packagefile, defaults to package.xml
 331       * - pathtopackagefile: the path to an existing package file to read in,
 332       *                      if different from the packagedirectory
 333       * - packagedirectory: the path to the base directory of the package.  For
 334       *                     package PEAR_PackageFileManager, this path is
 335       *                     /path/to/pearcvs/pear/PEAR_PackageFileManager where
 336       *                     /path/to/pearcvs is a local path on your hard drive
 337       * - outputdirectory: the path in which to place the generated package.xml
 338       *                    by default, this is ignored, and the package.xml is
 339       *                    created in the packagedirectory
 340       * - filelistgenerator: the <filelist> section plugin which will be used.
 341       *                      In this release, there are two generator plugins,
 342       *                      file and cvs.  For details, see the docs for these
 343       *                      plugins
 344       * - usergeneratordir: For advanced users.  If you write your own filelist
 345       *                     generator plugin, use this option to tell
 346       *                     PEAR_PackageFileManager where to find the file that
 347       *                     contains it.  If the plugin is named foo, the class
 348       *                     must be named PEAR_PackageFileManager_Foo
 349       *                     no matter where it is located.  By default, the Foo
 350       *                     plugin is located in PEAR/PackageFileManager/Foo.php.
 351       *                     If you pass /path/to/foo in this option, setOptions
 352       *                     will look for PEAR_PackageFileManager_Foo in
 353       *                     /path/to/foo/Foo.php
 354       * - doctype: Specifies the DTD of the package.xml file.  Default is
 355       *            http://pear.php.net/dtd/package-1.0
 356       * - pearcommonclass: Specifies the name of the class to instantiate, default
 357       *                    is PEAR_Common, but users can override this with a custom
 358       *                    class that implements PEAR_Common's method interface
 359       * - changelogoldtonew: True if the ChangeLog should list from oldest entry to
 360       *                      newest.  Set to false if you would like new entries first
 361       * - simpleoutput: True if the package.xml should not contain md5sum or <provides />
 362       *                 for readability
 363       * - addhiddenfiles: True if you wish to add hidden files/directories that begin with .
 364       *                   like .bashrc.  This is only used by the File generator.  The CVS
 365       *                   generator will use all files in CVS regardless of format
 366       *
 367       * package.xml simple options:
 368       * - baseinstalldir: The base directory to install this package in.  For
 369       *                   package PEAR_PackageFileManager, this is "PEAR", for
 370       *                   package PEAR, this is "/"
 371       * - license: The license this release is released under.  Default is
 372       *            PHP License if left unspecified
 373       * - notes: Release notes, any text describing what makes this release unique
 374       * - changelognotes: notes for the changelog, this should be more detailed than
 375       *                   the release notes.  By default, PEAR_PackageFileManager uses
 376       *                   the notes option for the changelog as well
 377       * - version: The version number for this release.  Remember the convention for
 378       *            numbering: initial alpha is between 0 and 1, add b<beta number> for
 379       *            beta as in 1.0b1, the integer portion of the version should specify
 380       *            backwards compatibility, as in 1.1 is backwards compatible with 1.0,
 381       *            but 2.0 is not backwards compatible with 1.10.  Also note that 1.10
 382       *            is a greater release version than 1.1 (think of it as "one point ten"
 383       *            and "one point one").  Bugfix releases should be a third decimal as in
 384       *            1.0.1, 1.0.2
 385       * - package: [optional] Package name.  Use this to create a new package.xml, or
 386       *            overwrite an existing one from another package used as a template
 387       * - summary: [optional] Summary of package purpose
 388       * - description: [optional] Description of package purpose.  Note that the above
 389       *                three options are not optional when creating a new package.xml
 390       *                from scratch
 391       *
 392       * <b>WARNING</b>: all complex options that require a file path are case-sensitive
 393       *
 394       * package.xml complex options:
 395       * - cleardependencies: since version 1.3.0, this option will erase any existing
 396       *                      dependencies in the package.xml if set to true
 397       * - ignore: an array of filenames, directory names, or wildcard expressions specifying
 398       *           files to exclude entirely from the package.xml.  Wildcards are operating system
 399       *           wildcards * and ?.  file*foo.php will exclude filefoo.php, fileabrfoo.php and
 400       *           filewho_is_thisfoo.php.  file?foo.php will exclude fileafoo.php and will not
 401       *           exclude fileaafoo.php.  test/ will exclude all directories and subdirectories of
 402       *           ANY directory named test encountered in directory parsing.  *test* will exclude
 403       *           all files and directories that contain test in their name
 404       * - include: an array of filenames, directory names, or wildcard expressions specifying
 405       *            files to include in the listing.  All other files will be ignored.
 406       *            Wildcards are in the same format as ignore
 407       * - roles: this is an array mapping file extension to install role.  This
 408       *          specifies default behavior that can be overridden by the exceptions
 409       *          option and dir_roles option.  use {@link addRole()} to add a new
 410       *          role to the pre-existing array
 411       * - dir_roles: this is an array mapping directory name to install role.  All
 412       *              files in a directory whose name matches the directory will be
 413       *              given the install role specified.  Single files can be excluded
 414       *              from this using the exceptions option.  The directory should be
 415       *              a relative path from the baseinstalldir, or "/" for the baseinstalldir
 416       * - exceptions: specify file role for specific files.  This array maps all files
 417       *               matching the exact name of a file to a role as in "file.ext" => "role"
 418       * - deps: dependency array.  Pass in an empty array to clear all dependencies, and use
 419       *         {@link addDependency()} to add new ones/replace existing ones
 420       * - maintainers: maintainers array.  Pass in an empty array to clear all maintainers, and
 421       *                use {@link addMaintainer()} to add a new maintainer/replace existing maintainer
 422       * - installexceptions: array mapping of specific filenames to baseinstalldir values.  Use
 423       *                      this to force the installation of a file into another directory,
 424       *                      such as forcing a script to be in the root scripts directory so that
 425       *                      it will be in the path.  The filename must be a relative path to the
 426       *                      packagedirectory
 427       * - platformexceptions: array mapping of specific filenames to the platform they should be
 428       *                       installed on.  Use this to specify unix-only files or windows-only
 429       *                       files.  The format of the platform string must be
 430       *                       OS-version-cpu-extra if any more specific information is needed,
 431       *                       and the OS must be in lower case as in "windows."  The match is
 432       *                       performed using a regular expression, but uses * and ? wildcards
 433       *                       instead of .* and .?.  Note that hpux/aix/irix/linux are all
 434       *                       exclusive.  To select non-windows, use (*ix|*ux)
 435       * - scriptphaseexceptions: array mapping of scripts to their install phase.  This can be
 436       *                          one of: pre-install, post-install, pre-uninstall, post-uninstall,
 437       *                          pre-build, post-build, pre-setup, or post-setup
 438       * - installas: array mapping of specific filenames to the filename they should be installed as.
 439       *              Use this to specify new filenames for files that should be installed.  This will
 440       *              often be used in conjunction with platformexceptions if there are two files for
 441       *              different OSes that must have the same name when installed.
 442       * - replacements: array mapping of specific filenames to complex text search-and-replace that
 443       *                 should be performed upon install.  The format is:
 444       *   <pre>
 445       *   filename => array('type' => php-const|pear-config|package-info
 446       *                     'from' => text in file
 447       *                     'to' => name of variable)
 448       *   </pre>
 449       *                 if type is php-const, then 'to' must be the name of a PHP Constant.
 450       *                 If type is pear-config, then 'to' must be the name of a PEAR config
 451       *                 variable accessible through a PEAR_Config class->get() method.  If
 452       *                 type is package-info, then 'to' must be the name of a section from
 453       *                 the package.xml file used to install this file.
 454       * - globalreplacements: a list of replacements that should be performed on every single file.
 455       *                       The format is the same as replacements (since 1.4.0)
 456       * - configure_options: array specifies build options for PECL packages (you should probably
 457       *                      use PECL_Gen instead, but it's here for completeness)
 458       * @see PEAR_PackageFileManager_File
 459       * @see PEAR_PackageFileManager_CVS
 460       * @return void|PEAR_Error
 461       * @throws PEAR_PACKAGEFILEMANAGER_NOSTATE
 462       * @throws PEAR_PACKAGEFILEMANAGER_NOVERSION
 463       * @throws PEAR_PACKAGEFILEMANAGER_NOPKGDIR
 464       * @throws PEAR_PACKAGEFILEMANAGER_NOBASEDIR
 465       * @throws PEAR_PACKAGEFILEMANAGER_GENERATOR_NOTFOUND_ANYWHERE
 466       * @throws PEAR_PACKAGEFILEMANAGER_GENERATOR_NOTFOUND
 467       * @param array
 468       */
 469      function setOptions($options = array(), $internal = false)
 470      {
 471          if (!$internal) {
 472              if (!isset($options['state'])) {
 473                  return $this->raiseError(PEAR_PACKAGEFILEMANAGER_NOSTATE);
 474              }
 475              if (!isset($options['version'])) {
 476                  return $this->raiseError(PEAR_PACKAGEFILEMANAGER_NOVERSION);
 477              }
 478          }
 479          if (!isset($options['packagedirectory']) && !$internal) {
 480              return $this->raiseError(PEAR_PACKAGEFILEMANAGER_NOPKGDIR);
 481          } elseif (isset($options['packagedirectory'])) {
 482              $options['packagedirectory'] = str_replace(DIRECTORY_SEPARATOR,
 483                                                       '/',
 484                                                       realpath($options['packagedirectory']));
 485              if ($options['packagedirectory']{strlen($options['packagedirectory']) - 1} != '/') {
 486                  $options['packagedirectory'] .= '/';
 487              }
 488          }
 489          if (isset($options['pathtopackagefile'])) {
 490              $options['pathtopackagefile'] = str_replace(DIRECTORY_SEPARATOR,
 491                                                       '/',
 492                                                       realpath($options['pathtopackagefile']));
 493              if ($options['pathtopackagefile']{strlen($options['pathtopackagefile']) - 1} != '/') {
 494                  $options['pathtopackagefile'] .= '/';
 495              }
 496          }
 497          if (!isset($options['baseinstalldir']) && !$internal) {
 498              return $this->raiseError(PEAR_PACKAGEFILEMANAGER_NOBASEDIR);
 499          }
 500          $this->_options = array_merge($this->_options, $options);
 501          
 502          if (!class_exists($this->_options['pearcommonclass'])) {
 503              if ($this->_options['simpleoutput']) {
 504                  if ($this->isIncludeable('PEAR/PackageFile/Generator/v1.php')) {
 505                      include_once  'PEAR/PackageFileManager/SimpleGenerator.php';
 506                      $this->_options['pearcommonclass'] = 'PEAR_PackageFileManager_SimpleGenerator';
 507                  } else {
 508                      include_once  'PEAR/PackageFileManager/XMLOutput.php';
 509                      $this->_options['pearcommonclass'] = 'PEAR_PackageFileManager_XMLOutput';
 510                  }
 511              } else {
 512                  $this->_options['pearcommonclass'] = 'PEAR_Common';
 513              }
 514          }
 515          $path = ($this->_options['pathtopackagefile'] ?
 516                      $this->_options['pathtopackagefile'] : $this->_options['packagedirectory']);
 517          $this->_options['filelistgenerator'] =
 518              ucfirst(strtolower($this->_options['filelistgenerator']));
 519          if (!$internal) {
 520              if (PEAR::isError($res =
 521                    $this->_getExistingPackageXML($path, $this->_options['packagefile']))) {
 522                  return $res;
 523              }
 524          }
 525          if (!class_exists('PEAR_PackageFileManager_' . $this->_options['filelistgenerator'])) {
 526              // attempt to load the interface from the standard PEAR location
 527              if ($this->isIncludeable('PEAR/PackageFileManager/' .
 528                    $this->_options['filelistgenerator'] . '.php')) {
 529                  include_once('PEAR/PackageFileManager/' .
 530                      $this->_options['filelistgenerator'] . '.php');
 531              } elseif (isset($this->_options['usergeneratordir'])) {
 532                  // attempt to load from a user-specified directory
 533                  if (is_dir(realpath($this->_options['usergeneratordir']))) {
 534                      $this->_options['usergeneratordir'] =
 535                          str_replace(DIRECTORY_SEPARATOR,
 536                                      '/',
 537                                      realpath($this->_options['usergeneratordir']));
 538                      if ($this->_options['usergeneratordir']{strlen($this->_options['usergeneratordir'])
 539                            - 1} != '/') {
 540                          $this->_options['usergeneratordir'] .= '/';
 541                      }
 542                  } else {
 543                      $this->_options['usergeneratordir'] = '////';
 544                  }
 545                  if (file_exists($this->_options['usergeneratordir'] .
 546                        $this->_options['filelistgenerator'] . '.php') &&
 547                        is_readable($this->_options['usergeneratordir'] .
 548                        $this->_options['filelistgenerator'] . '.php')) {
 549                      include_once($this->_options['usergeneratordir'] .
 550                          $this->_options['filelistgenerator'] . '.php');
 551                  }
 552                  if (!class_exists('PEAR_PackageFileManager_' . $this->_options['filelistgenerator'])) {
 553                      return $this->raiseError(PEAR_PACKAGEFILEMANAGER_GENERATOR_NOTFOUND_ANYWHERE,
 554                              'PEAR_PackageFileManager_' . $this->_options['filelistgenerator']);
 555                  }
 556              } else {
 557                  return $this->raiseError(PEAR_PACKAGEFILEMANAGER_GENERATOR_NOTFOUND,
 558                          'PEAR_PackageFileManager_' . $this->_options['filelistgenerator']);
 559              }
 560          }
 561      }
 562  
 563      /**
 564       * Import options from an existing package.xml
 565       *
 566       * @return true|PEAR_Error
 567       */
 568      function importOptions($packagefile, $options = array())
 569      {
 570          $options['cleardependencies'] = $options['deps'] = $options['maintainers'] = false;
 571          $this->setOptions($options, true);
 572          if (PEAR::isError($res = $this->_getExistingPackageXML(dirname($packagefile) .
 573                DIRECTORY_SEPARATOR, basename($packagefile)))) {
 574              return $res;
 575          }
 576          $this->_options['package'] = $this->_oldPackageXml['package'];
 577          $this->_options['summary'] = $this->_oldPackageXml['summary'];
 578          $this->_options['description'] = $this->_oldPackageXml['description'];
 579          $this->_options['date'] = $this->_oldPackageXml['release_date'];
 580          $this->_options['version'] = $this->_oldPackageXml['version'];
 581          $this->_options['license'] = $this->_oldPackageXml['release_license'];
 582          $this->_options['state'] = $this->_oldPackageXml['release_state'];
 583          $this->_options['notes'] = $this->_oldPackageXml['release_notes'];
 584          if (isset($this->_oldPackagexml['release_deps'])) {
 585              $this->_options['deps'] = $this->_oldPackageXml['release_deps'];
 586          }
 587          $this->_options['maintainers'] = $this->_oldPackageXml['maintainers'];
 588          return true;
 589      }
 590  
 591      /**
 592       * Get the existing options
 593       * @return array
 594       */
 595      function getOptions()
 596      {
 597          return $this->_options;
 598      }
 599  
 600      /**
 601       * Add an extension/role mapping to the role mapping option
 602       *
 603       * Roles influence both where a file is installed and how it is installed.
 604       * Files with role="data" are in a completely different directory hierarchy
 605       * from the program files of role="php"
 606       * 
 607       * In PEAR 1.3b2, these roles are
 608       * - php (most common)
 609       * - data
 610       * - doc
 611       * - test
 612       * - script (gives the file an executable attribute)
 613       * - src
 614       * @param string file extension
 615       * @param string role
 616       * @throws PEAR_PACKAGEFILEMANAGER_INVALID_ROLE
 617       */
 618      function addRole($extension, $role)
 619      {
 620          $roles = call_user_func(array($this->_options['pearcommonclass'], 'getfileroles'));
 621          if (!in_array($role, $roles)) {
 622              return $this->raiseError(PEAR_PACKAGEFILEMANAGER_INVALID_ROLE, implode($roles, ', '), $role);
 623          }
 624          $this->_options['roles'][$extension] = $role;
 625      }
 626      
 627      /**
 628       * Add an install-time platform conditional install for a file
 629       *
 630       * The format of the platform string must be
 631       * OS-version-cpu-extra if any more specific information is needed,
 632       * and the OS must be in lower case as in "windows."  The match is
 633       * performed using a regular expression, but uses * and ? wildcards
 634       * instead of .* and .?.  Note that hpux/aix/irix/linux are all
 635       * exclusive.  To select non-windows, use (*ix|*ux)
 636       *
 637       * This information is based on eyeing the source for OS/Guess.php, so
 638       * if you are unsure of what to do, read that file.
 639       * @param string relative path of file (relative to packagedirectory option)
 640       * @param string platform descriptor string
 641       */
 642      function addPlatformException($path, $platform)
 643      {
 644          if (!isset($this->_options['platformexceptions'])) {
 645              $this->_options['platformexceptions'] = array();
 646          }
 647          $this->_options['platformexceptions'][$path] = $platform;
 648      }
 649  
 650      /**
 651       * Add a replacement option for all files
 652       *
 653       * This sets an install-time complex search-and-replace function
 654       * allowing the setting of platform-specific variables in all
 655       * installed files.
 656       *
 657       * if $type is php-const, then $to must be the name of a PHP Constant.
 658       * If $type is pear-config, then $to must be the name of a PEAR config
 659       * variable accessible through a {@link PEAR_Config::get()} method.  If
 660       * type is package-info, then $to must be the name of a section from
 661       * the package.xml file used to install this file.
 662       * @param string relative path of file (relative to packagedirectory option)
 663       * @param string variable type, either php-const, pear-config or package-info
 664       * @param string text to replace in the source file
 665       * @param string variable name to use for replacement
 666       * @throws PEAR_PACKAGEFILEMANAGER_INVALID_REPLACETYPE
 667       */
 668      function addGlobalReplacement($type, $from, $to)
 669      {
 670          if (!isset($this->_options['globalreplacements'])) {
 671              $this->_options['globalreplacements'] = array();
 672          }
 673          $types = call_user_func(array($this->_options['pearcommonclass'], 'getreplacementtypes'));
 674          if (!in_array($type, $types)) {
 675              return $this->raiseError(PEAR_PACKAGEFILEMANAGER_INVALID_REPLACETYPE,
 676                  implode($types, ', '), $type);
 677          }
 678          $this->_options['globalreplacements'][] =
 679              array('type' => $type, 'from' => $from, 'to' => $to);
 680      }
 681  
 682      /**
 683       * Add a replacement option for a file
 684       *
 685       * This sets an install-time complex search-and-replace function
 686       * allowing the setting of platform-specific variables in an
 687       * installed file.
 688       *
 689       * if $type is php-const, then $to must be the name of a PHP Constant.
 690       * If $type is pear-config, then $to must be the name of a PEAR config
 691       * variable accessible through a {@link PEAR_Config::get()} method.  If
 692       * type is package-info, then $to must be the name of a section from
 693       * the package.xml file used to install this file.
 694       * @param string relative path of file (relative to packagedirectory option)
 695       * @param string variable type, either php-const, pear-config or package-info
 696       * @param string text to replace in the source file
 697       * @param string variable name to use for replacement
 698       * @throws PEAR_PACKAGEFILEMANAGER_INVALID_REPLACETYPE
 699       */
 700      function addReplacement($path, $type, $from, $to)
 701      {
 702          if (!isset($this->_options['replacements'])) {
 703              $this->_options['replacements'] = array();
 704          }
 705          $types = call_user_func(array($this->_options['pearcommonclass'], 'getreplacementtypes'));
 706          if (!in_array($type, $types)) {
 707              return $this->raiseError(PEAR_PACKAGEFILEMANAGER_INVALID_REPLACETYPE,
 708                  implode($types, ', '), $type);
 709          }
 710          $this->_options['replacements'][$path][] = array('type' => $type, 'from' => $from, 'to' => $to);
 711      }
 712      
 713      /**
 714       * Add a maintainer to the list of maintainers.
 715       *
 716       * Every maintainer must have a valid account at pear.php.net.  The
 717       * first parameter is the account name (for instance, cellog is the
 718       * handle for Greg Beaver at pear.php.net).  Every maintainer has
 719       * one of four possible roles:
 720       * - lead: the primary maintainer
 721       * - developer: an important developer on the project
 722       * - contributor: self-explanatory
 723       * - helper: ditto
 724       *
 725       * Finally, specify the name and email of the maintainer
 726       * @param string username on pear.php.net of maintainer
 727       * @param lead|developer|contributor|helper role of maintainer
 728       * @param string full name of maintainer
 729       * @param string email address of maintainer
 730       */
 731      function addMaintainer($handle, $role, $name, $email)
 732      {
 733          if (!$this->_packageXml) {
 734              return $this->raiseError(PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS);
 735          }
 736          if (!in_array($role, $GLOBALS['_PEAR_Common_maintainer_roles'])) {
 737              return $this->raiseError(PEAR_PACKAGEFILEMANAGER_WRONG_MROLE,
 738                  implode(', ', call_user_func(array($this->_options['pearcommonclass'],
 739                      'getUserRoles'))),
 740                  $role);
 741          }
 742          if (!isset($this->_packageXml['maintainers'])) {
 743              $this->_packageXml['maintainers'] = array();
 744          }
 745          $found = false;
 746          foreach($this->_packageXml['maintainers'] as $index => $maintainer) {
 747              if ($maintainer['handle'] == $handle) {
 748                  $found = $index;
 749                  break;
 750              }
 751          }
 752          $maintainer =
 753              array('handle' => $handle, 'role' => $role, 'name' => $name, 'email' => $email);
 754          if ($found !== false) {
 755              $this->_packageXml['maintainers'][$found] = $maintainer;
 756          } else {
 757              $this->_packageXml['maintainers'][] = $maintainer;
 758          }
 759      }
 760      
 761      /**
 762       * Add an install-time configuration option for building of source
 763       *
 764       * This option is only useful to PECL projects that are built upon
 765       * installation
 766       * @param string name of the option
 767       * @param string prompt to display to the user
 768       * @param string default value
 769       * @throws PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS
 770       * @return void|PEAR_Error
 771       */
 772      function addConfigureOption($name, $prompt, $default = null)
 773      {
 774          if (!$this->_packageXml) {
 775              return $this->raiseError(PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS);
 776          }
 777          if (!isset($this->_packageXml['configure_options'])) {
 778              $this->_packageXml['configure_options'] = array();
 779          }
 780          $found = false;
 781          foreach($this->_packageXml['configure_options'] as $index => $option) {
 782              if ($option['name'] == $name) {
 783                  $found = $index;
 784                  break;
 785              }
 786          }
 787          $option = array('name' => $name, 'prompt' => $prompt);
 788          if (isset($default)) {
 789              $option['default'] = $default;
 790          }
 791          if ($found !== false) {
 792              $this->_packageXml['configure_options'][$found] = $option;
 793          } else {
 794              $this->_packageXml['configure_options'][] = $option;
 795          }
 796      }
 797  
 798      /**
 799       * @return void|PEAR_Error
 800       * @throws PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS
 801       */
 802      function detectDependencies()
 803      {
 804          if (!$this->_packageXml) {
 805              return $this->raiseError(PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS);
 806          }
 807          if (!$this->isIncludeable('PHP/CompatInfo.php')) {
 808              return $this->raiseError(PEAR_PACKAGEFILEMANAGER_PHP_COMPAT_NOT_INSTALLED);
 809          } else {
 810              if (include_once('PHP/CompatInfo.php')) {
 811                  $this->_detectDependencies = true;
 812              } else {
 813                  $this->raiseError(PEAR_PACKAGEFILEMANAGER_NO_PHPCOMPATINFO);
 814              }
 815          }
 816      }
 817  
 818      function isIncludeable($file)
 819      {
 820          if (!defined('PATH_SEPARATOR')) {
 821              define('PATH_SEPARATOR', strtolower(substr(PHP_OS, 0, 3)) == 'win' ? ';' : ':');
 822          }
 823          foreach (explode(PATH_SEPARATOR, ini_get('include_path')) as $path) {
 824              if (file_exists($path . DIRECTORY_SEPARATOR . $file) &&
 825                    is_readable($path . DIRECTORY_SEPARATOR . $file)) {
 826                  return true;
 827              }
 828          }
 829          return false;
 830      }
 831  
 832      /**
 833       * Add a dependency on another package, or an extension/php
 834       *
 835       * This will overwrite an existing dependency if it is found.  In
 836       * other words, if a dependency on PHP 4.1.0 exists, and
 837       * addDependency('php', '4.3.0', 'ge', 'php') is called, the existing
 838       * dependency on PHP 4.1.0 will be overwritten with the new one on PHP 4.3.0
 839       * @param string Dependency element name
 840       * @param string Dependency version
 841       * @param string A specific operator for the version, this can be one of:
 842       *   'has', 'not', 'lt', 'le', 'eq', 'ne', 'ge', or 'gt'
 843       * @param string Dependency type.  This can be one of:
 844       *   'pkg', 'ext', 'php', 'prog', 'os', 'sapi', or 'zend'
 845       * @param boolean true if dependency is optional
 846       * @throws PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS
 847       * @throws PEAR_PACKAGEFILEMANAGER_PHP_NOT_PACKAGE
 848       * @return void|PEAR_Error
 849       */
 850      function addDependency($name, $version = false, $operator = 'ge', $type = 'pkg', $optional = false)
 851      {
 852          if (!$this->_packageXml) {
 853              return $this->raiseError(PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS);
 854          }
 855          if ((strtolower($name) == 'php') && (strtolower($type) == 'pkg')) {
 856              return $this->raiseError(PEAR_PACKAGEFILEMANAGER_PHP_NOT_PACKAGE);
 857          }
 858          if (!isset($this->_packageXml['release_deps']) || !is_array($this->_packageXml['release_deps'])) {
 859              $this->_packageXml['release_deps'] = array();
 860          }
 861          $found = false;
 862          foreach($this->_packageXml['release_deps'] as $index => $dep) {
 863              if ($type == 'php') {
 864                  if ($dep['type'] == 'php') {
 865                      $found = $index;
 866                      break;
 867                  }
 868              } else {
 869                  if (isset($dep['name']) && $dep['name'] == $name && $dep['type'] == $type) {
 870                      $found = $index;
 871                      break;
 872                  }
 873              }
 874          }
 875          $dep =
 876              array(
 877                  'name' => $name,
 878                  'type' => $type);
 879          if ($type == 'php') {
 880              unset($dep['name']);
 881          }
 882          if ($operator) {
 883              $dep['rel'] = $operator;
 884              if ($dep['rel'] != 'has' && $version) {
 885                  $dep['version'] = $version;
 886              }
 887          }
 888          
 889          if ($optional) {
 890              $dep['optional'] = 'yes';
 891          } else {
 892              $dep['optional'] = 'no';
 893          }
 894  
 895          if ($found !== false) {
 896              $this->_packageXml['release_deps'][$found] = $dep; // overwrite existing dependency
 897          } else {
 898              $this->_packageXml['release_deps'][] = $dep; // add new dependency
 899          }
 900      }
 901  
 902      /**
 903       * Writes the package.xml file out with the newly created <release></release> tag
 904       *
 905       * ALWAYS use {@link debugPackageFile} to verify that output is correct before
 906       * overwriting your package.xml
 907       * @param boolean null if no debugging, true if web interface, false if command-line
 908       * @throws PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS
 909       * @throws PEAR_PACKAGEFILEMANAGER_ADD_MAINTAINERS
 910       * @throws PEAR_PACKAGEFILEMANAGER_CANTWRITE_PKGFILE
 911       * @throws PEAR_PACKAGEFILEMANAGER_CANTCOPY_PKGFILE
 912       * @throws PEAR_PACKAGEFILEMANAGER_CANTOPEN_TMPPKGFILE
 913       * @throws PEAR_PACKAGEFILEMANAGER_DEST_UNWRITABLE
 914       * @return void|PEAR_Error
 915       */
 916      function writePackageFile($debuginterface = null)
 917      {
 918          if (!$this->_packageXml) {
 919              return $this->raiseError(PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS);
 920          }
 921          if (!isset($this->_packageXml['maintainers']) || empty($this->_packageXml['maintainers'])) {
 922              return $this->raiseError(PEAR_PACKAGEFILEMANAGER_ADD_MAINTAINERS);
 923          }
 924          extract($this->_options);
 925          $date = date('Y-m-d');
 926          if (isset($package)) {
 927              $this->_packageXml['package'] = $package;
 928          }
 929          if (isset($summary)) {
 930              $this->_packageXml['summary'] = $summary;
 931          }
 932          if (isset($description)) {
 933              $this->_packageXml['description'] = $description;
 934          }
 935          $this->_packageXml['release_date'] = $date;
 936          $this->_packageXml['version'] = $version;
 937          $this->_packageXml['release_license'] = $license;
 938          $this->_packageXml['release_state'] = $state;
 939          $this->_packageXml['release_notes'] = $notes;
 940          $PEAR_Common = $this->_options['pearcommonclass'];
 941          $this->_pear = new $PEAR_Common;
 942          if (method_exists($this->_pear, 'setPackageFileManager')) {
 943              $this->_pear->setPackageFileManager($this);
 944          }
 945          $this->_packageXml['filelist'] = $this->_getFileList();
 946          $warnings = $this->getWarnings();
 947          if (count($warnings)) {
 948              $nl = (isset($debuginterface) && $debuginterface ? '<br />' : "\n");
 949              foreach($warnings as $errmsg) {
 950                  echo 'WARNING: ' . $errmsg['message'] . $nl;
 951              }
 952          }
 953          if (PEAR::isError($this->_packageXml['filelist'])) {
 954              return $this->_packageXml['filelist'];
 955          }
 956          if (isset($this->_pear->pkginfo['provides'])) {
 957              $this->_packageXml['provides'] = $this->_pear->pkginfo['provides'];
 958          }
 959          if ($this->_options['simpleoutput']) {
 960              unset($this->_packageXml['provides']);
 961          }
 962          $this->_packageXml['release_deps'] = $this->_getDependencies();
 963          $this->_updateChangeLog();
 964          
 965          $common = &$this->_pear;
 966          $warnings = $errors = array();
 967          if (method_exists($common, 'setPackageFileManagerOptions')) {
 968              $common->setPackageFileManagerOptions($this->_options);
 969          }
 970          $packagexml = $common->xmlFromInfo($this->_packageXml);
 971          $common->validatePackageInfo($packagexml, $warnings, $errors,
 972              $this->_options['packagedirectory']);
 973          if (count($errors)) {
 974              $ret = '';
 975              $nl = (isset($debuginterface) && $debuginterface ? '<br />' : "\n");
 976              foreach($errors as $errmsg) {
 977                  $ret .= $errmsg . $nl;
 978              }
 979              return $this->raiseError(PEAR_PACKAGEFILEMANAGER_INVALID_PACKAGE, $nl, $ret);
 980          }
 981          if (count($warnings)) {
 982              $nl = (isset($debuginterface) && $debuginterface ? '<br />' : "\n");
 983              foreach($warnings as $errmsg) {
 984                  echo $errmsg . $nl;
 985              }
 986          }
 987          if (!strpos($packagexml, '<!DOCTYPE')) {
 988              // hack to fix pear
 989              $packagexml = str_replace('<package version="1.0">',
 990                  '<!DOCTYPE package SYSTEM "' . $this->_options['doctype'] .
 991                  "\">\n<package version=\"1.0\">",
 992                  $packagexml);
 993          }
 994          if (isset($debuginterface)) {
 995              if ($debuginterface) {
 996                  echo '<pre>' . htmlentities($packagexml) . '</pre>';
 997              } else {
 998                  echo $packagexml;
 999              }
1000              return true;
1001          }
1002          $outputdir = ($this->_options['outputdirectory'] ?
1003                          $this->_options['outputdirectory'] : $this->_options['packagedirectory']);
1004          if ((file_exists($outputdir . $this->_options['packagefile']) &&
1005                  is_writable($outputdir . $this->_options['packagefile']))
1006                  ||
1007                  @touch($outputdir . $this->_options['packagefile'])) {
1008              if ($fp = @fopen($outputdir . $this->_options['packagefile'] . '.tmp', "w")) {
1009                  $written = @fwrite($fp, $packagexml);
1010                  @fclose($fp);
1011                  if ($written === false) {
1012                      return $this->raiseError(PEAR_PACKAGEFILEMANAGER_CANTWRITE_PKGFILE);
1013                  }
1014                  if (!@copy($outputdir . $this->_options['packagefile'] . '.tmp',
1015                          $outputdir . $this->_options['packagefile'])) {
1016                      return $this->raiseError(PEAR_PACKAGEFILEMANAGER_CANTCOPY_PKGFILE);
1017                  } else {
1018                      @unlink($outputdir . $this->_options['packagefile'] . '.tmp');
1019                      return true;
1020                  }
1021              } else {
1022                  return $this->raiseError(PEAR_PACKAGEFILEMANAGER_CANTOPEN_TMPPKGFILE,
1023                      $outputdir . $this->_options['packagefile'] . '.tmp');
1024              }
1025          } else {
1026              return $this->raiseError(PEAR_PACKAGEFILEMANAGER_DEST_UNWRITABLE, $outputdir);
1027          }
1028      }
1029      
1030      /**
1031       * ALWAYS use this to test output before overwriting your package.xml!!
1032       *
1033       * This method instructs writePackageFile() to simply print the package.xml
1034       * to output, either command-line or web-friendly (this is automatic
1035       * based on the value of php_sapi_name())
1036       * @uses writePackageFile() calls with the debug parameter set based on
1037       *       whether it is called from the command-line or web interface
1038       */
1039      function debugPackageFile()
1040      {
1041          $webinterface = php_sapi_name() != 'cli';
1042          return $this->writePackageFile($webinterface);
1043      }
1044      
1045      /**
1046       * Store a warning on the warning stack
1047       */
1048      function pushWarning($code, $info)
1049      {
1050          $this->_warningStack[] = array('code' => $code,
1051                                         'message' => $this->_getMessage($code, $info));
1052      }
1053      
1054      /**
1055       * Retrieve the list of warnings
1056       * @return array
1057       */
1058      function getWarnings()
1059      {
1060          $a = $this->_warningStack;
1061          $this->_warningStack = array();
1062          return $a;
1063      }
1064      
1065      /**
1066       * Retrieve an error message from a code
1067       * @access private
1068       * @return string Error message
1069       */
1070      function _getMessage($code, $info)
1071      {
1072          $msg = $GLOBALS['_PEAR_PACKAGEFILEMANAGER_ERRORS'][$this->_options['lang']][$code];
1073          foreach ($info as $name => $value) {
1074              $msg = str_replace('%' . $name . '%', $value, $msg);
1075          }
1076          return $msg;
1077      }
1078      
1079      /**
1080       * Utility function to shorten error generation code
1081       *
1082       * {@source}
1083       * @return PEAR_Error
1084       * @static
1085       */
1086      function raiseError($code, $i1 = '', $i2 = '')
1087      {
1088          return PEAR::raiseError('PEAR_PackageFileManager Error: ' .
1089                      sprintf($GLOBALS['_PEAR_PACKAGEFILEMANAGER_ERRORS'][$this->_options['lang']][$code],
1090                      $i1, $i2), $code);
1091      }
1092      
1093      /**
1094       * Uses {@link PEAR_Common::analyzeSourceCode()} and {@link PEAR_Common::buildProvidesArray()}
1095       * to create the <provides></provides> section of the package.xml
1096       * @param PEAR_Common
1097       * @param string path to source file
1098       * @access private
1099       */
1100      function _addProvides(&$pear, $file)
1101      {
1102          if (!($a = $pear->analyzeSourceCode($file))) {
1103              return;
1104          } else {
1105              $pear->buildProvidesArray($a);
1106          }
1107      }
1108      
1109      /**
1110       * @uses getDirTag() generate the xml from the array
1111       * @return string
1112       * @access private
1113       */
1114      function _getFileList()
1115      {
1116          $generatorclass = 'PEAR_PackageFileManager_' . $this->_options['filelistgenerator'];
1117          $generator = new $generatorclass($this, $this->_options);
1118          if ($this->_options['simpleoutput'] && is_a($this->_pear, 'PEAR_Common')) {
1119              return $this->_getSimpleDirTag($this->_struc = $generator->getFileList());
1120          }
1121          return $this->_getDirTag($this->_struc = $generator->getFileList()); 
1122      }
1123      
1124      /**
1125       * Recursively generate the <filelist> section's <dir> and <file> tags, but with
1126       * simple human-readable output
1127       * @param array|PEAR_Error the sorted directory structure, or an error
1128       *                         from filelist generation
1129       * @param false|string whether the parent directory has a role this should
1130       * inherit
1131       * @param integer indentation level
1132       * @return array|PEAR_Error
1133       * @access private
1134       */
1135      function _getSimpleDirTag($struc, $role = false, $_curdir = '')
1136      {
1137          if (PEAR::isError($struc)) {
1138              return $struc;
1139          }
1140          extract($this->_options);
1141          $ret = array();
1142          foreach($struc as $dir => $files) {
1143              if (false && $dir === '/') {
1144                  // global directory role? overrides all exceptions except file exceptions
1145                  if (isset($dir_roles['/'])) {
1146                      $role = $dir_roles['/'];
1147                  }
1148                  return array(
1149                      'baseinstalldir' => $this->_options['baseinstalldir'],
1150                      '##files' => $this->_getSimpleDirTag($struc[$dir], $role, ''),
1151                      'name' => '/');
1152              } else {
1153                  if (!isset($files['file'])) {
1154                      if (isset($dir_roles[$_curdir . $dir])) {
1155                          $myrole = $dir_roles[$_curdir . $dir];
1156                      } else {
1157                          $myrole = $role;
1158                      }
1159                      $ret[$dir] = array();
1160                      if ($dir == '/') {
1161                          $ret[$dir]['baseinstalldir'] = $this->_options['baseinstalldir'];
1162                      }
1163                      $ret[$dir]['name'] = $dir;
1164                      $recurdir = ($_curdir == '') ? $dir . '/' : $_curdir . $dir . '/';
1165                      if ($recurdir == '//') {
1166                          $recurdir = '';
1167                      }
1168                      $ret[$dir]['##files'] = $this->_getSimpleDirTag($files, $myrole, $recurdir);
1169                  } else {
1170                      $myrole = '';
1171                      if (!$role)
1172                      {
1173                          $myrole = false;
1174                          if (isset($exceptions[$files['path']])) {
1175                              $myrole = $exceptions[$files['path']];
1176                          } elseif (isset($roles[$files['ext']])) {
1177                              $myrole = $roles[$files['ext']];
1178                          } else {
1179                              $myrole = $roles['*'];
1180                          }
1181                      } else {
1182                          $myrole = $role;
1183                          if (isset($exceptions[$files['path']])) {
1184                              $myrole = $exceptions[$files['path']];
1185                          }
1186                      }
1187                      $test = explode('/', $files['path']);
1188                      foreach ($test as $subpath) {
1189                          if ($subpath == 'CVS') {
1190                              $this->pushWarning(PEAR_PACKAGEFILEMANAGER_CVS_PACKAGED,
1191                                  array('path' => $files['path']));
1192                          }
1193                      }
1194                      $ret[$files['file']] = array('role' => $myrole);
1195                      if (isset($installexceptions[$files['path']])) {
1196                          $ret[$files['file']]['baseinstalldir'] =
1197                              $installexceptions[$files['path']];
1198                      }
1199                      if (isset($platformexceptions[$files['path']])) {
1200                          $ret[$files['file']]['platform'] = $platformexceptions[$files['path']];
1201                      }
1202                      if (isset($installas[$files['path']])) {
1203                          $ret[$files['file']]['install-as'] = $installas[$files['path']];
1204                      }
1205                      if (isset($replacements[$files['path']])) {
1206                          $ret[$files['file']]['replacements'] = $replacements[$files['path']];
1207                      }
1208                      if (isset($globalreplacements)) {
1209                          if (!isset($ret[$files['file']]['replacements'])) {
1210                              $ret[$files['file']]['replacements'] = array();
1211                          }
1212                          $ret[$files['file']]['replacements'] = array_merge(
1213                              $ret[$files['file']]['replacements'], $globalreplacements);
1214                      }
1215                  }
1216              }
1217          }
1218          return $ret;
1219      }
1220      
1221      /**
1222       * Recursively generate the <filelist> section's <dir> and <file> tags
1223       * @param array|PEAR_Error the sorted directory structure, or an error
1224       *                         from filelist generation
1225       * @param false|string whether the parent directory has a role this should
1226       * inherit
1227       * @param integer indentation level
1228       * @return array|PEAR_Error
1229       * @access private
1230       */
1231      function _getDirTag($struc, $role=false, $_curdir = '')
1232      {
1233          if (PEAR::isError($struc)) {
1234              return $struc;
1235          }
1236          extract($this->_options);
1237          $ret = array();
1238          foreach($struc as $dir => $files) {
1239              if ($dir === '/') {
1240                  // global directory role? overrides all exceptions except file exceptions
1241                  if (isset($dir_roles['/'])) {
1242                      $role = $dir_roles['/'];
1243                  }
1244                  return $this->_getDirTag($struc[$dir], $role, '');
1245              } else {
1246                  if (!isset($files['file'])) {
1247                      $myrole = '';
1248                      if (isset($dir_roles[$_curdir . $dir])) {
1249                          $myrole = $dir_roles[$_curdir . $dir];
1250                      } elseif ($role) {
1251                          $myrole = $role;
1252                      }
1253                      $ret = array_merge($ret, $this->_getDirTag($files, $myrole, $_curdir . $dir . '/'));
1254                  } else {
1255                      $myrole = '';
1256                      if (!$role)
1257                      {
1258                          $myrole = false;
1259                          if (isset($exceptions[$files['path']])) {
1260                              $myrole = $exceptions[$files['path']];
1261                          } elseif (isset($roles[$files['ext']])) {
1262                              $myrole = $roles[$files['ext']];
1263                          } else {
1264                              $myrole = $roles['*'];
1265                          }
1266                      } else {
1267                          $myrole = $role;
1268                          if (isset($exceptions[$files['path']])) {
1269                              $myrole = $exceptions[$files['path']];
1270                          }
1271                      }
1272                      if (isset($installexceptions[$files['path']])) {
1273                          $bi = $installexceptions[$files['path']];
1274                      } else {
1275                          $bi = $this->_options['baseinstalldir'];
1276                      }
1277                      $test = explode('/', $files['path']);
1278                      foreach ($test as $subpath) {
1279                          if ($subpath == 'CVS') {
1280                              $this->pushWarning(PEAR_PACKAGEFILEMANAGER_CVS_PACKAGED, array('path' => $files['path']));
1281                          }
1282                      }
1283                      $ret[$files['path']] =
1284                          array('role' => $myrole,
1285                                'baseinstalldir' => $bi,
1286                                );
1287                      if (!isset($this->_options['simpleoutput'])) {
1288                          $md5sum = @md5_file($this->_options['packagedirectory'] . $files['path']);
1289                          if (!empty($md5sum)) {
1290                              $ret[$files['path']]['md5sum'] = $md5sum;
1291                          }
1292                      } elseif (isset($ret[$files['path']]['md5sum'])) {
1293                          unset($ret[$files['path']]['md5sum']);
1294                      }
1295                      if (isset($platformexceptions[$files['path']])) {
1296                          $ret[$files['path']]['platform'] = $platformexceptions[$files['path']];
1297                      }
1298                      if (isset($installas[$files['path']])) {
1299                          $ret[$files['path']]['install-as'] = $installas[$files['path']];
1300                      }
1301                      if (isset($replacements[$files['path']])) {
1302                          $ret[$files['path']]['replacements'] = $replacements[$files['path']];
1303                      }
1304                      if (isset($globalreplacements)) {
1305                          if (!isset($ret[$files['path']]['replacements'])) {
1306                              $ret[$files['path']]['replacements'] = array();
1307                          }
1308                          $ret[$files['path']]['replacements'] = array_merge(
1309                              $ret[$files['path']]['replacements'], $globalreplacements);
1310                      }
1311                      if ($myrole == 'php' && !$this->_options['simpleoutput']) {
1312                          $this->_addProvides($this->_pear, $files['fullpath']);
1313                      }
1314                  }
1315              }
1316          }
1317          return $ret;
1318      }
1319  
1320      /**
1321       * @param array
1322       * @access private
1323       */
1324      function _traverseFileArray($files, &$ret) {
1325          foreach ($files as $file) {
1326              if (!isset($file['fullpath'])) {
1327                  $this->_traverseFileArray($file, $ret);
1328              } else {
1329                  $ret[] = $file['fullpath'];
1330              }
1331          }
1332      }
1333  
1334      /**
1335       * Retrieve the 'deps' option passed to the constructor
1336       * @access private
1337       * @return array
1338       */
1339      function _getDependencies()
1340      {
1341          if ($this->_detectDependencies) {
1342              $this->_traverseFileArray($this->_struc, $ret);
1343              $compatinfo = new PHP_CompatInfo();
1344              $info = $compatinfo->parseArray($ret);
1345              $ret = $this->addDependency('php',$info['version'],'ge','php',false);
1346              if (is_a($ret, 'PEAR_Error')) {
1347                  return $ret;
1348              }
1349              foreach ($info['extensions'] as $ext) {
1350                  $this->addDependency($ext, '', 'has', 'ext', false);
1351              }
1352          }
1353          if (isset($this->_packageXml['release_deps']) &&
1354                is_array($this->_packageXml['release_deps'])) {
1355              return $this->_packageXml['release_deps'];
1356          } else {
1357              return array();
1358          }
1359      }
1360  
1361      /**
1362       * Creates a changelog entry with the current release
1363       * notes and dates, or overwrites a previous creation
1364       * @access private
1365       */
1366      function _updateChangeLog()
1367      {
1368          $curlog = $oldchangelog = false;
1369          if (!isset($this->_packageXml['changelog'])) {
1370              $changelog = array();
1371              if (isset($this->_oldPackageXml['release_notes'])) {
1372                  $changelog['release_notes'] = $this->_oldPackageXml['release_notes'];
1373              }
1374              if (isset($this->_oldPackageXml['version'])) {
1375                  $changelog['version'] = $this->_oldPackageXml['version'];
1376              }
1377              if (isset($this->_oldPackageXml['release_date'])) {
1378                  $changelog['release_date'] = $this->_oldPackageXml['release_date'];
1379              }
1380              if (isset($this->_oldPackageXml['release_license'])) {
1381                  $changelog['release_license'] = $this->_oldPackageXml['release_license'];
1382              }
1383              if (isset($this->_oldPackageXml['release_state'])) {
1384                  $changelog['release_state'] = $this->_oldPackageXml['release_state'];
1385              }
1386              if (count($changelog)) {
1387                  $this->_packageXml['changelog'] = array($changelog);
1388              } else {
1389                  $this->_packageXml['changelog'] = array();
1390              }
1391          } else {
1392              if (isset($this->_oldPackageXml['release_notes'])) {
1393                  $oldchangelog['release_notes'] = $this->_oldPackageXml['release_notes'];
1394              }
1395              if (isset($this->_oldPackageXml['version'])) {
1396                  $oldchangelog['version'] = $this->_oldPackageXml['version'];
1397              }
1398              if (isset($this->_oldPackageXml['release_date'])) {
1399                  $oldchangelog['release_date'] = $this->_oldPackageXml['release_date'];
1400              }
1401              if (isset($this->_oldPackageXml['release_license'])) {
1402                  $oldchangelog['release_license'] = $this->_oldPackageXml['release_license'];
1403              }
1404              if (isset($this->_oldPackageXml['release_state'])) {
1405                  $oldchangelog['release_state'] = $this->_oldPackageXml['release_state'];
1406              }
1407          }
1408          $hasoldversion = false;
1409          foreach($this->_packageXml['changelog'] as $index => $changelog) {
1410              if ($oldchangelog && isset($oldchangelog['version']) 
1411                      && strnatcasecmp($oldchangelog['version'], $changelog['version']) == 0) {
1412                  $hasoldversion = true;
1413              }
1414              if (isset($changelog['version']) && strnatcasecmp($changelog['version'], $this->_options['version']) == 0) {
1415                  $curlog = $index;
1416              }
1417              if (isset($this->_packageXml['changelog'][$index]['release_notes'])) {
1418                  $this->_packageXml['changelog'][$index]['release_notes'] = trim($changelog['release_notes']);
1419              }
1420              // the parsing of the release notes adds a \n for some reason
1421          }
1422          if (!$hasoldversion && $oldchangelog && count($oldchangelog)
1423                && $oldchangelog['version'] != $this->_options['version']) {
1424              $this->_packageXml['changelog'][] = $oldchangelog;
1425          }
1426          $notes = ($this->_options['changelognotes'] ?
1427                      $this->_options['changelognotes'] : $this->_options['notes']);
1428          $changelog = array('version' => $this->_options['version'],
1429                             'release_date' => date('Y-m-d'),
1430                             'release_license' => $this->_options['license'],
1431                             'release_state' => $this->_options['state'],
1432                             'release_notes' => $notes,
1433                             );
1434          if ($curlog !== false) {
1435              $this->_packageXml['changelog'][$curlog] = $changelog;
1436          } else {
1437              $this->_packageXml['changelog'][] = $changelog;
1438          }
1439          usort($this->_packageXml['changelog'], array($this, '_changelogsort'));
1440      }
1441      
1442      /**
1443       * @static
1444       * @access private
1445       */
1446      function _changelogsort($a, $b)
1447      {
1448          if ($this->_options['changelogoldtonew']) {
1449              $c = strtotime($a['release_date']);
1450              $d = strtotime($b['release_date']);
1451              $v1 = $a['version'];
1452              $v2 = $b['version'];
1453           } else {
1454              $d = strtotime($a['release_date']);
1455              $c = strtotime($b['release_date']);
1456              $v2 = $a['version'];
1457              $v1 = $b['version'];
1458          }
1459          if ($c - $d > 0) {
1460              return 1;
1461          } elseif ($c - $d < 0) {
1462              return -1;
1463           }
1464          return version_compare($v1, $v2);
1465      }
1466  
1467      /**
1468       * @return true|PEAR_Error
1469       * @uses _generateNewPackageXML() if no package.xml is found, it
1470       *       calls this to create a new one
1471       * @param string full path to package file
1472       * @param string name of package file
1473       * @throws PEAR_PACKAGEFILEMANAGER_PATH_DOESNT_EXIST
1474       * @access private
1475       */
1476      function _getExistingPackageXML($path, $packagefile = 'package.xml')
1477      {
1478          if (is_string($path) && is_dir($path)) {
1479              $contents = false;
1480              if (file_exists($path . $packagefile)) {
1481                  $contents = file_get_contents($path . $packagefile);
1482              }
1483              if (!$contents) {
1484                  return $this->_generateNewPackageXML();
1485              } else {
1486                  $PEAR_Common = $this->_options['pearcommonclass'];
1487                  if (!class_exists($PEAR_Common)) {
1488                      return $this->raiseError(PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS);
1489                  }
1490                  $common = new $PEAR_Common;
1491                  if (is_a($common, 'PEAR_Common')) {
1492                      $this->_oldPackageXml =
1493                      $this->_packageXml = $common->infoFromString($contents);
1494                  } else { // new way
1495                      require_once  'PEAR/PackageFile.php';
1496                      $z = &PEAR_Config::singleton();
1497                      $pkg = &new PEAR_PackageFile($z);
1498                      $pf = &$pkg->fromXmlString($contents, PEAR_VALIDATE_DOWNLOADING, $path . $packagefile);
1499                      if (PEAR::isError($pf)) {
1500                          return $pf;
1501                      }
1502                      if ($pf->getPackagexmlVersion() != '1.0') {
1503                          return PEAR::raiseError('PEAR_PackageFileManager can only manage ' .
1504                              'package.xml version 1.0, use PEAR_PackageFileManager_v2 for newer' .
1505                              ' package files');
1506                      }
1507                      $this->_oldPackageXml =
1508                      $this->_packageXml = $pf->toArray();
1509                  }
1510                  if (PEAR::isError($this->_packageXml)) {
1511                      return $this->_packageXml;
1512                  }
1513                  if ($this->_options['cleardependencies']) {
1514                      $this->_packageXml['release_deps'] = $this->_options['deps'];
1515                  }
1516                  if ($this->_options['deps'] !== false) {
1517                      $this->_packageXml['release_deps'] = $this->_options['deps'];
1518                  } else {
1519                      if (isset($this->_packageXml['release_deps'])) {
1520                          $this->_options['deps'] = $this->_packageXml['release_deps'];
1521                      }
1522                  }
1523                  if ($this->_options['maintainers'] !== false) {
1524                      $this->_packageXml['maintainers'] = $this->_options['maintainers'];
1525                  } else {
1526                      $this->_options['maintainers'] = $this->_packageXml['maintainers'];
1527                  }
1528                  unset($this->_packageXml['filelist']);
1529                  unset($this->_packageXml['provides']);
1530              }
1531              return true;
1532          } else {
1533              if (!is_string($path)) {
1534                  $path = gettype($path);
1535              }
1536              return $this->raiseError(PEAR_PACKAGEFILEMANAGER_PATH_DOESNT_EXIST,
1537                  $path);
1538          }
1539      }
1540      
1541      /**
1542       * Create the structure for a new package.xml
1543       *
1544       * @uses $_packageXml emulates reading in a package.xml
1545       *       by using the package, summary and description
1546       *       options
1547       * @return true|PEAR_Error
1548       * @access private
1549       */
1550      function _generateNewPackageXML()
1551      {
1552          $this->_oldPackageXml = false;
1553          if (!isset($this->_options['package'])) {
1554              return $this->raiseError(PEAR_PACKAGEFILEMANAGER_NOPACKAGE);
1555          }
1556          if (!isset($this->_options['summary'])) {
1557              return $this->raiseError(PEAR_PACKAGEFILEMANAGER_NOSUMMARY);
1558          }
1559          if (!isset($this->_options['description'])) {
1560              return $this->raiseError(PEAR_PACKAGEFILEMANAGER_NODESC);
1561          }
1562          $this->_packageXml = array();
1563          $this->_packageXml['package'] = $this->_options['package'];
1564          $this->_packageXml['summary'] = $this->_options['summary'];
1565          $this->_packageXml['description'] = $this->_options['description'];
1566          $this->_packageXml['changelog'] = array();
1567          if ($this->_options['deps'] !== false) {
1568              $this->_packageXml['release_deps'] = $this->_options['deps'];
1569          } else {
1570              $this->_packageXml['release_deps'] = $this->_options['deps'] = array();
1571          }
1572          if ($this->_options['maintainers'] !== false) {
1573              $this->_packageXml['maintainers'] = $this->_options['maintainers'];
1574          } else {
1575              $this->_packageXml['maintainers'] = $this->_options['maintainers'] = array();
1576          }
1577          return true;
1578      }
1579  }
1580  
1581  if (!function_exists('file_get_contents')) {
1582  /**
1583   * @ignore
1584   */
1585  function file_get_contents($path, $use_include_path = null, $context = null)
1586  {
1587      $a = @file($path, $use_include_path, $context);
1588      if (is_array($a)) {
1589          return implode('', $a);
1590      } else {
1591          return false;
1592      }
1593  }
1594  }
1595  ?>


Généré le : Sun Feb 25 14:08:00 2007 par Balluche grâce à PHPXref 0.7