phpDocumentor PEAR_PackageFileManager
[ class tree: PEAR_PackageFileManager ] [ index: PEAR_PackageFileManager ] [ all elements ]

Source for file PackageFileManager.php

Documentation is available at PackageFileManager.php


1 <?php
2 //
3 // +------------------------------------------------------------------------+
4 // | PEAR :: Package File Manager |
5 // +------------------------------------------------------------------------+
6 // | Copyright (c) 2003 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 //
20
21 /**
22 * @package PEAR_PackageFileManager
23 */
24 /**
25 * PEAR installer
26 */
27 require_once 'PEAR/Common.php';
28 /**#@+
29 * Error Codes
30 */
31 define('PEAR_PACKAGEFILEMANAGER_NOSTATE', 1);
32 define('PEAR_PACKAGEFILEMANAGER_NOVERSION', 2);
33 define('PEAR_PACKAGEFILEMANAGER_NOPKGDIR', 3);
34 define('PEAR_PACKAGEFILEMANAGER_NOBASEDIR', 3);
35 define('PEAR_PACKAGEFILEMANAGER_GENERATOR_NOTFOUND', 4);
36 define('PEAR_PACKAGEFILEMANAGER_GENERATOR_NOTFOUND_ANYWHERE', 5);
37 define('PEAR_PACKAGEFILEMANAGER_CANTWRITE_PKGFILE', 6);
38 define('PEAR_PACKAGEFILEMANAGER_DEST_UNWRITABLE', 7);
39 define('PEAR_PACKAGEFILEMANAGER_CANTCOPY_PKGFILE', 8);
40 define('PEAR_PACKAGEFILEMANAGER_CANTOPEN_TMPPKGFILE', 9);
41 define('PEAR_PACKAGEFILEMANAGER_PATH_DOESNT_EXIST', 10);
42 define('PEAR_PACKAGEFILEMANAGER_NOCVSENTRIES', 11);
43 define('PEAR_PACKAGEFILEMANAGER_DIR_DOESNT_EXIST', 12);
44 define('PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS', 13);
45 define('PEAR_PACKAGEFILEMANAGER_NOPACKAGE', 14);
46 define('PEAR_PACKAGEFILEMANAGER_WRONG_MROLE', 15);
47 define('PEAR_PACKAGEFILEMANAGER_NOSUMMARY', 16);
48 define('PEAR_PACKAGEFILEMANAGER_NODESC', 17);
49 define('PEAR_PACKAGEFILEMANAGER_ADD_MAINTAINERS', 18);
50 define('PEAR_PACKAGEFILEMANAGER_NO_FILES', 19);
51 define('PEAR_PACKAGEFILEMANAGER_IGNORED_EVERYTHING', 20);
52 /**#@-*/
53 /**
54 * Error messages
55 * @global array $GLOBALS['_PEAR_PACKAGEFILEMANAGER_ERRORS']
56 */
57 $GLOBALS['_PEAR_PACKAGEFILEMANAGER_ERRORS'] =
58 array(
59 'en' =>
60 array(
61 PEAR_PACKAGEFILEMANAGER_NOSTATE =>
62 'Release State (option \'state\') must by specified in PEAR_PackageFileManager setOptions (alpha|beta|stable)',
63 PEAR_PACKAGEFILEMANAGER_NOVERSION =>
64 'Release Version (option \'version\') must be specified in PEAR_PackageFileManager setOptions',
65 PEAR_PACKAGEFILEMANAGER_NOPKGDIR =>
66 'Package source base directory (option \'packagedirectory\') must be ' .
67 'specified in PEAR_PackageFileManager setOptions',
68 PEAR_PACKAGEFILEMANAGER_NOPKGDIR =>
69 'Package install base directory (option \'baseinstalldir\') must be ' .
70 'specified in PEAR_PackageFileManager setOptions',
71 PEAR_PACKAGEFILEMANAGER_GENERATOR_NOTFOUND =>
72 'Base class "%s" can\'t be located',
73 PEAR_PACKAGEFILEMANAGER_GENERATOR_NOTFOUND_ANYWHERE =>
74 'Base class "%s" can\'t be located in default or user-specified directories',
75 PEAR_PACKAGEFILEMANAGER_CANTWRITE_PKGFILE =>
76 'Failed to write package.xml file to destination directory',
77 PEAR_PACKAGEFILEMANAGER_DEST_UNWRITABLE =>
78 'Destination directory "%s" is unwritable',
79 PEAR_PACKAGEFILEMANAGER_CANTCOPY_PKGFILE =>
80 'Failed to copy package.xml.tmp file to package.xml',
81 PEAR_PACKAGEFILEMANAGER_CANTOPEN_TMPPKGFILE =>
82 'Failed to open temporary file "%s" for writing',
83 PEAR_PACKAGEFILEMANAGER_PATH_DOESNT_EXIST =>
84 'package.xml file path "%s" doesn\'t exist or isn\'t a directory',
85 PEAR_PACKAGEFILEMANAGER_NOCVSENTRIES =>
86 'Directory "%s" is not a CVS directory (it must have the CVS/Entries file)',
87 PEAR_PACKAGEFILEMANAGER_DIR_DOESNT_EXIST =>
88 'Package source base directory "%s" doesn\'t exist or isn\'t a directory',
89 PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS =>
90 'Run $managerclass->setOptions() before any other methods',
91 PEAR_PACKAGEFILEMANAGER_NOPACKAGE =>
92 'Package Name (option \'package\') must by specified in PEAR_PackageFileManager '.
93 'setOptions to create a new package.xml',
94 PEAR_PACKAGEFILEMANAGER_NOSUMMARY =>
95 'Package Summary (option \'summary\') must by specified in PEAR_PackageFileManager' .
96 ' setOptions to create a new package.xml',
97 PEAR_PACKAGEFILEMANAGER_NODESC =>
98 'Detailed Package Description (option \'description\') must be' .
99 ' specified in PEAR_PackageFileManager constructor to create a new package.xml',
100 PEAR_PACKAGEFILEMANAGER_WRONG_MROLE =>
101 'Maintainer role must be one of "%s", was "%s"',
102 PEAR_PACKAGEFILEMANAGER_ADD_MAINTAINERS =>
103 'Add maintainers to a package before generating the package.xml',
104 PEAR_PACKAGEFILEMANAGER_NO_FILES =>
105 'No files found, check the path "%s"',
106 PEAR_PACKAGEFILEMANAGER_IGNORED_EVERYTHING =>
107 'No files left, check the path "%s" and ignore option "%s"',
108 ),
109 // other language translations go here
110 );
111 /**
112 * PEAR :: PackageGenerate updates the <filelist></filelist> section
113 * of a PEAR package.xml file to reflect the current files in
114 * preparation for a release.
115 *
116 * The PEAR_PackageGenerate class uses a plugin system to generate the
117 * list of files in a package. This allows both standard recursive
118 * directory parsing (plugin type file) and more intelligent options
119 * such as the CVS browser {@link PEAR_PackageFileManager_Cvs}, which
120 * grabs all files in a local CVS checkout to create the list, ignoring
121 * any other local files.
122 *
123 * Other options include specifying roles for file extensions (all .php
124 * files are role="php", for example), roles for directories (all directories
125 * named "tests" are given role="tests" by default), and exceptions.
126 * Exceptions are specific pathnames with * and ? wildcards that match
127 * a default role, but should have another. For example, perhaps
128 * a debug.tpl template would normally be data, but should be included
129 * in the docs role. Along these lines, to exclude files entirely,
130 * use the ignore option.
131 *
132 * Required options for a release include version, baseinstalldir, state,
133 * and packagedirectory (the full path to the local location of the
134 * package to create a package.xml file for)
135 *
136 * Example usage:
137 * <code>
138 * <?php
139 * require_once('PEAR/PackageFileManager.php');
140 * $packagexml = new PEAR_PackageFileManager;
141 * $e = $packagexml->setOptions(
142 * array('baseinstalldir' => 'PhpDocumentor',
143 * 'version' => '1.2.1',
144 * 'packagedirectory' => 'C:/Web Pages/chiara/phpdoc2/',
145 * 'state' => 'stable',
146 * 'filelistgenerator' => 'cvs', // generate from cvs, use file for directory
147 * 'notes' => 'We\'ve implemented many new and exciting features',
148 * 'ignore' => array('TODO', 'tests/'), // ignore TODO, all files in tests/
149 * 'installexceptions' => array('phpdoc' => '/*'), // baseinstalldir ="/" for phpdoc
150 * 'dir_roles' => array('tutorials' => 'doc'),
151 * 'exceptions' => array('README' => 'doc', // README would be data, now is doc
152 * 'PHPLICENSE.txt' => 'doc'))); // same for the license
153 * if (PEAR::isError($e)) {
154 * echo $e->getMessage();
155 * die();
156 * }
157 * $packagexml->addRole('pkg', 'doc'); // add a new role mapping
158 * $e = $packagexml->writePackageFile();
159 * if (PEAR::isError($e)) {
160 * echo $e->getMessage();
161 * die();
162 * }
163 * ?>
164 *
165 * In addition, a package.xml file can now be generated from
166 * scratch, with the usage of new options package, summary, description, and
167 * the use of the {@link addMaintainer()} method
168 * </code>
169 * @package PEAR_PackageFileManager
170 */
171 class PEAR_PackageFileManager
172 {
173 /**
174 * Format: array(array(regexp-ready string to search for whole path,
175 * regexp-ready string to search for basename of ignore strings),...)
176 * @var false|array
177 * @access private
178 */
179 var $_ignore = false;
180
181 /**
182 * Contents of the package.xml file
183 * @var string
184 * @access private
185 */
186 var $_packageXml = false;
187
188 /**
189 * @access private
190 * @var PEAR_Common
191 */
192 var $_pear;
193
194 /**
195 * @access private
196 * @var string
197 */
198 var $_options = array(
199 'packagefile' => 'package.xml',
200 'doctype' => 'http://pear.php.net/dtd/package-1.0',
201 'filelistgenerator' => 'file',
202 'license' => 'PHP License',
203 'roles' =>
204 array(
205 'php' => 'php',
206 'html' => 'doc',
207 '*' => 'data',
208 ),
209 'dir_roles' =>
210 array(
211 'docs' => 'doc',
212 'examples' => 'doc',
213 'tests' => 'tests',
214 ),
215 'exceptions' => array(),
216 'installexceptions' => array(),
217 'ignore' => array(),
218 'deps' => false,
219 'maintainers' => false,
220 'notes' => '',
221 'changelognotes' => false,
222 'outputdirectory' => false,
223 'pathtopackagefile' => false,
224 'lang' => 'en',
225 'configure_options' => array(),
226 );
227
228 /**
229 * Does nothing, use setOptions
230 * @see setOptions
231 */
232 function PEAR_PackageFileManager()
233 {
234 }
235
236 /**
237 * Set package.xml generation options
238 *
239 * The options array is indexed as follows:
240 * <code>
241 * $options = array('option_name' => <optionvalue>);
242 * </code>
243 *
244 * The documentation below simplifies this description through
245 * the use of option_name without quotes
246 *
247 * Configuration options:
248 * - lang: lang controls the language in which error messages are
249 * displayed. There are currently only English error messages,
250 * but any contributed will be added over time.<br />
251 * Possible values: en (default)
252 * - packagefile: the name of the packagefile, defaults to package.xml
253 * - pathtopackagefile: the path to an existing package file to read in,
254 * if different from the packagedirectory
255 * - packagedirectory: the path to the base directory of the package. For
256 * package PEAR_PackageFileManager, this path is
257 * /path/to/pearcvs/pear/PEAR_PackageFileManager where
258 * /path/to/pearcvs is a local path on your hard drive
259 * - outputdirectory: the path in which to place the generated package.xml
260 * by default, this is ignored, and the package.xml is
261 * created in the packagedirectory
262 * - filelistgenerator: the <filelist> section plugin which will be used.
263 * In this release, there are two generator plugins,
264 * file and cvs. For details, see the docs for these
265 * plugins
266 * - usergeneratordir: For advanced users. If you write your own filelist
267 * generator plugin, use this option to tell
268 * PEAR_PackageFileManager where to find the file that
269 * contains it. If the plugin is named foo, the class
270 * must be named PEAR_PackageFileManager_Foo
271 * no matter where it is located. By default, the Foo
272 * plugin is located in PEAR/PackageFileManager/Foo.php.
273 * If you pass /path/to/foo in this option, setOptions
274 * will look for PEAR_PackageFileManager_Foo in
275 * /path/to/foo/Foo.php
276 * - doctype: Specifies the DTD of the package.xml file. Default is
277 * http://pear.php.net/dtd/package-1.0
278 *
279 * package.xml simple options:
280 * - baseinstalldir: The base directory to install this package in. For
281 * package PEAR_PackageFileManager, this is "PEAR", for
282 * package PEAR, this is "/"
283 * - license: The license this release is released under. Default is
284 * PHP License if left unspecified
285 * - notes: Release notes, any text describing what makes this release unique
286 * - changelognotes: notes for the changelog, this should be more detailed than
287 * the release notes. By default, PEAR_PackageFileManager uses
288 * the notes option for the changelog as well
289 * - version: The version number for this release. Remember the convention for
290 * numbering: initial alpha is between 0 and 1, add b<beta number> for
291 * beta as in 1.0b1, the integer portion of the version should specify
292 * backwards compatibility, as in 1.1 is backwards compatible with 1.0,
293 * but 2.0 is not backwards compatible with 1.10. Also note that 1.10
294 * is a greater release version than 1.1 (think of it as "one point ten"
295 * and "one point one"). Bugfix releases should be a third decimal as in
296 * 1.0.1, 1.0.2
297 * - package: [optional] Package name. Use this to create a new package.xml, or
298 * overwrite an existing one from another package used as a template
299 * - summary: [optional] Summary of package purpose
300 * - description: [optional] Description of package purpose. Note that the above
301 * three options are not optional when creating a new package.xml
302 * from scratch
303 *
304 * package.xml complex options:
305 * - roles: this is an array mapping file extension to install role. This
306 * specifies default behavior that can be overridden by the exceptions
307 * option and dir_roles option. use {@link addRole()} to add a new
308 * role to the pre-existing array
309 * - dir_roles: this is an array mapping directory name to install role. All
310 * files in a directory whose name matches the directory will be
311 * given the install role specified. Single files can be excluded
312 * from this using the exceptions option. The directory should be
313 * a relative path from the baseinstalldir, or "/" for the baseinstalldir
314 * - exceptions: specify file role for specific files. This array maps all files
315 * matching the exact name of a file to a role as in "file.ext" => "role"
316 * - installexceptions: array mapping of specific filenames to baseinstalldir values. Use
317 * this to force the installation of a file into another directory,
318 * such as forcing a script to be in the root scripts directory so that
319 * it will be in the path
320 * - deps: dependency array. Pass in an empty array to clear all dependencies, and use
321 * {@link addDependency()} to add new ones/replace existing ones
322 * - maintainers: maintainers array. Pass in an empty array to clear all maintainers, and
323 * use {@link addMaintainer()} to add a new maintainer/replace existing maintainer
324 * - configure_options: array specifies build options for PECL packages (you should probably
325 * use PECL_Gen instead, but it's here for completeness)
326 * - ignore: an array of filenames, directory names, or wildcard expressions specifying
327 * files to exclude entirely from the package.xml. Wildcards are operating system
328 * wildcards * and ?. file*foo.php will exclude filefoo.php, fileabrfoo.php and
329 * filewho_is_thisfoo.php. file?foo.php will exclude fileafoo.php and will not
330 * exclude fileaafoo.php. test/ will exclude all directories and subdirectories of
331 * ANY directory named test encountered in directory parsing. *test* will exclude
332 * all files and directories that contain test in their name
333 * @see PEAR_PackageFileManager_Generator_File
334 * @see PEAR_PackageFileManager_Generator_CVS
335 * @return void|PEAR_Error
336 * @throws PEAR_PACKAGEFILEMANAGER_NOSTATE
337 * @throws PEAR_PACKAGEFILEMANAGER_NOVERSION
338 * @throws PEAR_PACKAGEFILEMANAGER_NOPKGDIR
339 * @throws PEAR_PACKAGEFILEMANAGER_NOBASEDIR
340 * @throws PEAR_PACKAGEFILEMANAGER_GENERATOR_NOTFOUND_ANYWHERE
341 * @throws PEAR_PACKAGEFILEMANAGER_GENERATOR_NOTFOUND
342 * @param array
343 */
344 function setOptions($options = array())
345 {
346 if (!isset($options['state'])) {
347 return $this->raiseError(PEAR_PACKAGEFILEMANAGER_NOSTATE);
348 }
349 if (!isset($options['version'])) {
350 return $this->raiseError(PEAR_PACKAGEFILEMANAGER_NOVERSION);
351 }
352 if (!isset($options['packagedirectory'])) {
353 return $this->raiseError(PEAR_PACKAGEFILEMANAGER_NOPKGDIR);
354 } else {
355 $options['packagedirectory'] = str_replace(DIRECTORY_SEPARATOR,
356 '/',
357 realpath($options['packagedirectory']));
358 if ($options['packagedirectory']{strlen($options['packagedirectory']) - 1} != '/') {
359 $options['packagedirectory'] .= '/';
360 }
361 }
362 if (!isset($options['baseinstalldir'])) {
363 return $this->raiseError(PEAR_PACKAGEFILEMANAGER_NOBASEDIR);
364 }
365 $this->_options = array_merge($this->_options, $options);
366
367 $path = ($this->_options['pathtopackagefile'] ?
368 $this->_options['pathtopackagefile'] : $this->_options['packagedirectory']);
369 $this->_options['filelistgenerator'] = ucfirst(strtolower($this->_options['filelistgenerator']));
370 if (PEAR::isError($res = $this->_getExistingPackageXML($path, $this->_options['packagefile']))) {
371 return $res;
372 }
373 // attempt to load the interface from the standard PEAR location
374 @include_once('PEAR/PackageFileManager/' . $this->_options['filelistgenerator'] . '.php');
375 if (!class_exists('PEAR_PackageFileManager_' . $this->_options['filelistgenerator'])) {
376 if (isset($this->_options['usergeneratordir'])) {
377 // attempt to load from a user-specified directory
378 $this->_options['usergeneratordir'] = str_replace(DIRECTORY_SEPARATOR,
379 '/',
380 realpath($this->_options['usergeneratordir']));
381 if ($this->_options['usergeneratordir']{strlen($this->_options['usergeneratordir']) - 1} != '/') {
382 $this->_options['usergeneratordir'] .= '/';
383 }
384 @include_once($this->_options['usergeneratordir'] . $this->_options['filelistgenerator'] . '.php');
385 if (!class_exists('PEAR_PackageFileManager_' . $this->_options['filelistgenerator'])) {
386 return $this->raiseError(PEAR_PACKAGEFILEMANAGER_GENERATOR_NOTFOUND_ANYWHERE,
387 'PEAR_PackageFileManager_' . $this->_options['filelistgenerator']);
388 }
389 } else {
390 return $this->raiseError(PEAR_PACKAGEFILEMANAGER_GENERATOR_NOTFOUND,
391 'PEAR_PackageFileManager_' . $this->_options['filelistgenerator']);
392 }
393 }
394 }
395
396 /**
397 * Add an extension/role mapping to the role mapping option
398 * @param string file extension
399 * @param string role
400 */
401 function addRole($extension, $role)
402 {
403 $this->_options['roles'][$extension] = $role;
404 }
405
406 /**
407 * Add a maintainer to the list of maintainers.
408 *
409 * Every maintainer must have a valid account at pear.php.net. The
410 * first parameter is the account name (for instance, cellog is the
411 * handle for Greg Beaver at pear.php.net). Every maintainer has
412 * one of four possible roles:
413 * - lead: the primary maintainer
414 * - developer: an important developer on the project
415 * - contributor: self-explanatory
416 * - helper: ditto
417 *
418 * Finally, specify the name and email of the maintainer
419 * @param string username on pear.php.net of maintainer
420 * @param lead|developer|contributor|helperrole of maintainer
421 * @param string full name of maintainer
422 * @param string email address of maintainer
423 */
424 function addMaintainer($handle, $role, $name, $email)
425 {
426 if (!$this->_packageXml) {
427 return $this->raiseError(PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS);
428 }
429 if (!in_array($role, $GLOBALS['_PEAR_Common_maintainer_roles'])) {
430 return $this->raiseError(PEAR_PACKAGEFILEMANAGER_WRONG_MROLE,
431 implode(', ', $GLOBALS['_PEAR_Common_maintainer_roles']),
432 $role);
433 }
434 if (!isset($this->_packageXml['maintainers'])) {
435 $this->_packageXml['maintainers'] = array();
436 }
437 $found = false;
438 foreach($this->_packageXml['maintainers'] as $index => $maintainer) {
439 if ($maintainer['handle'] == $handle) {
440 $found = $index;
441 break;
442 }
443 }
444 $maintainer =
445 array('handle' => $handle, 'role' => $role, 'name' => $name, 'email' => $email);
446 if ($found !== false) {
447 $this->_packageXml['maintainers'][$found] = $maintainer;
448 } else {
449 $this->_packageXml['maintainers'][] = $maintainer;
450 }
451 }
452
453 /**
454 * Add an install-time configuration option for building of source
455 *
456 * This option is only useful to PECL projects that are built upon
457 * installation
458 * @param string name of the option
459 * @param string prompt to display to the user
460 * @param string default value
461 * @throws PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS
462 * @return void|PEAR_Error
463 */
464 function addConfigureOption($name, $prompt, $default = null)
465 {
466 if (!$this->_packageXml) {
467 return $this->raiseError(PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS);
468 }
469 if (!isset($this->_packageXml['configure_options'])) {
470 $this->_packageXml['configure_options'] = array();
471 }
472 $found = false;
473 foreach($this->_packageXml['configure_options'] as $index => $option) {
474 if ($option['name'] == $name) {
475 $found = $index;
476 break;
477 }
478 }
479 $option = array('name' => $name, 'prompt' => $prompt);
480 if (isset($default)) {
481 $option['default'] = $default;
482 }
483 if ($found !== false) {
484 $this->_packageXml['configure_options'][$found] = $option;
485 } else {
486 $this->_packageXml['configure_options'][] = $option;
487 }
488 }
489
490 /**
491 * Add a dependency on another package, or an extension/php
492 *
493 * This will overwrite an existing dependency if it is found. In
494 * other words, if a dependency on PHP 4.1.0 exists, and
495 * addDependency('php', '4.3.0', 'ge', 'php') is called, the existing
496 * dependency on PHP 4.1.0 will be overwritten with the new one on PHP 4.3.0
497 * @param string Dependency element name
498 * @param string Dependency version
499 * @param string A specific operator for the version, this can be one of:
500 * 'has', 'not', 'lt', 'le', 'eq', 'ne', 'ge', or 'gt'
501 * @param string Dependency type. This can be one of:
502 * 'pkg', 'ext', 'php', 'prog', 'os', 'sapi', or 'zend'
503 * @throws PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS
504 * @return void|PEAR_Error
505 */
506 function addDependency($name, $version = false, $operator = 'ge', $type = 'pkg')
507 {
508 if (!$this->_packageXml) {
509 return $this->raiseError(PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS);
510 }
511 if (!isset($this->_packageXml['release_deps'])) {
512 $this->_packageXml['release_deps'] = array();
513 }
514 $found = false;
515 foreach($this->_packageXml['release_deps'] as $index => $dep) {
516 if ($type == 'php') {
517 if ($dep['type'] == 'php') {
518 $found = $index;
519 break;
520 }
521 } else {
522 if (isset($dep['name']) && $dep['name'] == $name && $dep['type'] == $type) {
523 $found = $index;
524 break;
525 }
526 }
527 }
528 $dep =
529 array(
530 'name' => $name,
531 'type' => $type);
532 if ($type == 'php') {
533 unset($dep['name']);
534 }
535 if ($version) {
536 $dep['version'] = $version;
537 if ($operator) {
538 $dep['rel'] = $operator;
539 }
540 }
541
542 if ($found !== false) {
543 $this->_packageXml['release_deps'][$found] = $dep; // overwrite existing dependency
544 } else {
545 $this->_packageXml['release_deps'][] = $dep; // add new dependency
546 }
547 }
548
549 /**
550 * Writes the package.xml file out with the newly created <release></release> tag
551 *
552 * ALWAYS use {@link debugPackageFile} to verify that output is correct before
553 * overwriting your package.xml
554 * @param boolean null if no debugging, true if web interface, false if command-line
555 * @throws PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS
556 * @throws PEAR_PACKAGEFILEMANAGER_ADD_MAINTAINERS
557 * @throws PEAR_PACKAGEFILEMANAGER_CANTWRITE_PKGFILE
558 * @throws PEAR_PACKAGEFILEMANAGER_CANTCOPY_PKGFILE
559 * @throws PEAR_PACKAGEFILEMANAGER_CANTOPEN_TMPPKGFILE
560 * @throws PEAR_PACKAGEFILEMANAGER_DEST_UNWRITABLE
561 * @return void|PEAR_Error
562 */
563 function writePackageFile($debuginterface = null)
564 {
565 if (!$this->_packageXml) {
566 return $this->raiseError(PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS);
567 }
568 if (!isset($this->_packageXml['maintainers']) || empty($this->_packageXml['maintainers'])) {
569 return $this->raiseError(PEAR_PACKAGEFILEMANAGER_ADD_MAINTAINERS);
570 }
571 extract($this->_options);
572 $date = date('Y-m-d');
573 if (isset($package)) {
574 $this->_packageXml['package'] = $package;
575 }
576 if (isset($summary)) {
577 $this->_packageXml['summary'] = $summary;
578 }
579 if (isset($description)) {
580 $this->_packageXml['description'] = $description;
581 }
582 $this->_packageXml['release_date'] = $date;
583 $this->_packageXml['version'] = $version;
584 $this->_packageXml['release_license'] = $license;
585 $this->_packageXml['release_state'] = $state;
586 $this->_packageXml['release_notes'] = $notes;
587 $this->_pear = new PEAR_Common;
588 $this->_packageXml['filelist'] = $this->_getFileList();
589 if (PEAR::isError($this->_packageXml['filelist'])) {
590 return $this->_packageXml['filelist'];
591 }
592 if (isset($this->_pear->pkginfo['provides'])) {
593 $this->_packageXml['provides'] = $this->_pear->pkginfo['provides'];
594 }
595 $this->_packageXml['release_deps'] = $this->_getDependencies();
596 $this->_updateChangeLog();
597 $common = &$this->_pear;
598 $packagexml = $common->xmlFromInfo($this->_packageXml);
599 if (!strpos($packagexml, '<!DOCTYPE')) {
600 // hack to fix pear
601 $packagexml = str_replace('<package version="1.0">',
602 '<!DOCTYPE package SYSTEM "' . $this->_options['doctype'] .
603 "\">\n<package version=\"1.0\">",
604 $packagexml);
605 }
606 if (isset($debuginterface)) {
607 if ($debuginterface) {
608 echo '<pre>' . htmlentities($packagexml) . '</pre>';
609 } else {
610 echo $packagexml;
611 }
612 return true;
613 }
614 $outputdir = ($this->_options['outputdirectory'] ?
615 $this->_options['outputdirectory'] : $this->_options['packagedirectory']);
616 if ((file_exists($outputdir . $this->_options['packagefile']) &&
617 is_writable($outputdir . $this->_options['packagefile']))
618 ||
619 @touch($outputdir . $this->_options['packagefile'])) {
620 if ($fp = @fopen($outputdir . $this->_options['packagefile'] . '.tmp', "w")) {
621 $written = @fwrite($fp, $packagexml);
622 @fclose($fp);
623 if ($written === false) {
624 return $this->raiseError(PEAR_PACKAGEFILEMANAGER_CANTWRITE_PKGFILE);
625 }
626 if (!@copy($outputdir . $this->_options['packagefile'] . '.tmp',
627 $outputdir . $this->_options['packagefile'])) {
628 return $this->raiseError(PEAR_PACKAGEFILEMANAGER_CANTCOPY_PKGFILE);
629 } else {
630 @unlink($outputdir . $this->_options['packagefile'] . '.tmp');
631 return true;
632 }
633 } else {
634 return $this->raiseError(PEAR_PACKAGEFILEMANAGER_CANTOPEN_TMPPKGFILE,
635 $outputdir . $this->_options['packagefile'] . '.tmp');
636 }
637 } else {
638 return $this->raiseError(PEAR_PACKAGEFILEMANAGER_DEST_UNWRITABLE, $outputdir);
639 }
640 }
641
642 /**
643 * ALWAYS use this to test output before overwriting your package.xml!!
644 * @uses writePackageFile() calls with the debug parameter set based on
645 * whether it is called from the command-line or web interface
646 */
647 function debugPackageFile()
648 {
649 $webinterface = isset($_SERVER['PATH_TRANSLATED']);
650 return $this->writePackageFile($webinterface);
651 }
652
653 /**
654 * Utility function to shorten error generation code
655 *
656 * {@source }
657 * @return PEAR_Error
658 * @static
659 */
660 function raiseError($code, $i1 = '', $i2 = '')
661 {
662 return PEAR::raiseError('PEAR_PackageFileManager Error: ' .
663 sprintf($GLOBALS['_PEAR_PACKAGEFILEMANAGER_ERRORS'][$this->_options['lang']][$code],
664 $i1, $i2));
665 }
666
667 /**
668 * Uses {@link PEAR_Common::analyzeSourceCode()} and {@link PEAR_Common::buildProvidesArray()}
669 * to create the <provides></provides> section of the package.xml
670 * @param PEAR_Common
671 * @param string path to source file
672 * @access private
673 */
674 function _addProvides(&$pear, $file)
675 {
676 if (!($a = $pear->analyzeSourceCode($file))) {
677 return;
678 } else {
679 $pear->buildProvidesArray($a);
680 }
681 }
682
683 /**
684 * @uses getDirTag() generate the xml from the array
685 * @return string
686 * @access private
687 */
688 function _getFileList()
689 {
690 $generatorclass = 'PEAR_PackageFileManager_' . $this->_options['filelistgenerator'];
691 $generator = new $generatorclass($this, $this->_options);
692 return $this->_getDirTag($generator->getFileList());
693 }
694
695 /**
696 * Recursively generate the <filelist> section's <dir> and <file> tags
697 * @param array|PEAR_Errorthe sorted directory structure, or an error
698 * from filelist generation
699 * @param false|stringwhether the parent directory has a role this should
700 * inherit
701 * @param integer indentation level
702 * @return array|PEAR_Error
703 * @access private
704 */
705 function _getDirTag($struc, $role=false)
706 {
707 if (PEAR::isError($struc)) {
708 return $struc;
709 }
710 extract($this->_options);
711 $ret = array();
712 foreach($struc as $dir => $files) {
713 if ($dir === '/') {
714 return $this->_getDirTag($struc[$dir], $role);
715 } else {
716 if (!isset($files['file'])) {
717 $myrole = '';
718 if ($role) {
719 $myrole = $role;
720 } elseif (isset($dir_roles[$dir])) {
721 $myrole = $dir_roles[$dir];
722 }
723 $ret = array_merge($ret, $this->_getDirTag($files, $myrole));
724 } else {
725 $myrole = '';
726 if (!$role)
727 {
728 $myrole = false;
729 if (isset($exceptions[$files['file']])) {
730 $myrole = $exceptions[$files['file']];
731 } elseif (isset($roles[$files['ext']])) {
732 $myrole = $roles[$files['ext']];
733 } else {
734 $myrole = $roles['*'];
735 }
736 } else {
737 $myrole = $role;
738 }
739 if (isset($installexceptions[$files['file']])) {
740 $bi = $installexceptions[$files['file']];
741 } else {
742 $bi = $baseinstalldir;
743 }
744 $ret[$files['path']] = array('role' => $myrole, 'baseinstalldir' => $bi);
745 if ($myrole == 'php') {
746 $this->_addProvides($this->_pear, $files['fullpath']);
747 }
748 }
749 }
750 }
751 return $ret;
752 }
753
754 /**
755 * Retrieve the 'deps' option passed to the constructor
756 * @access private
757 * @return array
758 */
759 function _getDependencies()
760 {
761 if ($this->_packageXml['release_deps']) {
762 return $this->_packageXml['release_deps'];
763 } else {
764 return array();
765 }
766 }
767
768 /**
769 * Creates a changelog entry with the current release
770 * notes and dates, or overwrites a previous creation
771 * @access private
772 */
773 function _updateChangeLog()
774 {
775 $curlog = false;
776 foreach($this->_packageXml['changelog'] as $index => $changelog) {
777 if ($changelog['version'] == $this->_options['version']) {
778 $curlog = $index;
779 }
780 if (isset($this->_packageXml['changelog'][$index]['release_notes'])) {
781 $this->_packageXml['changelog'][$index]['release_notes'] = trim($changelog['release_notes']);
782 }
783 // the parsing of the release notes adds a \n for some reason
784 }
785 $notes = ($this->_options['changelognotes'] ?
786 $this->_options['changelognotes'] : $this->_options['notes']);
787 $changelog = array('version' => $this->_options['version'],
788 'release_date' => date('Y-m-d'),
789 'release_license' => $this->_options['license'],
790 'release_state' => $this->_options['state'],
791 'release_notes' => $notes,
792 );
793 if ($curlog !== false) {
794 $this->_packageXml['changelog'][$curlog] = $changelog;
795 } else {
796 $this->_packageXml['changelog'][] = $changelog;
797 }
798 }
799
800 /**
801 * @return true|PEAR_Error
802 * @uses _generateNewPackageXML() if no package.xml is found, it
803 * calls this to create a new one
804 * @param string full path to package file
805 * @param string name of package file
806 * @throws PEAR_PACKAGEFILEMANAGER_PATH_DOESNT_EXIST
807 * @access private
808 */
809 function _getExistingPackageXML($path, $packagefile = 'package.xml')
810 {
811 if (@is_dir($path)) {
812 $contents = @file_get_contents($path . $packagefile);
813 if (!$contents) {
814 return $this->_generateNewPackageXML();
815 } else {
816 $common = new PEAR_Common;
817 $this->_packageXml = $common->infoFromString($contents);
818 if (PEAR::isError($this->_packageXml)) {
819 return $this->_packageXml;
820 }
821 if ($this->_options['deps'] !== false) {
822 $this->_packageXml['release_deps'] = $this->_options['deps'];
823 } else {
824 $this->_options['deps'] = $this->_packageXml['release_deps'];
825 }
826 if ($this->_options['maintainers'] !== false) {
827 $this->_packageXml['maintainers'] = $this->_options['maintainers'];
828 } else {
829 $this->_options['maintainers'] = $this->_packageXml['maintainers'];
830 }
831 unset($this->_packageXml['filelist']);
832 unset($this->_packageXml['provides']);
833 }
834 return true;
835 } else {
836 return $this->raiseError(PEAR_PACKAGEFILEMANAGER_PATH_DOESNT_EXIST,
837 $path);
838 }
839 }
840
841 /**
842 * Create the structure for a new package.xml
843 *
844 * @uses $_packageXml emulates reading in a package.xml
845 * by using the package, summary and description
846 * options
847 * @return true|PEAR_Error
848 * @access private
849 */
850 function _generateNewPackageXML()
851 {
852 if (!isset($this->_options['package'])) {
853 return $this->raiseError(PEAR_PACKAGEFILEMANAGER_NOPACKAGE);
854 }
855 if (!isset($this->_options['summary'])) {
856 return $this->raiseError(PEAR_PACKAGEFILEMANAGER_NOSUMMARY);
857 }
858 if (!isset($this->_options['description'])) {
859 return $this->raiseError(PEAR_PACKAGEFILEMANAGER_NODESC);
860 }
861 $this->_packageXml = array();
862 $this->_packageXml['package'] = $this->_options['package'];
863 $this->_packageXml['summary'] = $this->_options['summary'];
864 $this->_packageXml['description'] = $this->_options['description'];
865 $this->_packageXml['changelog'] = array();
866 if ($this->_options['deps'] !== false) {
867 $this->_packageXml['release_deps'] = $this->_options['deps'];
868 } else {
869 $this->_packageXml['release_deps'] = $this->_options['deps'] = array();
870 }
871 if ($this->_options['maintainers'] !== false) {
872 $this->_packageXml['maintainers'] = $this->_options['maintainers'];
873 } else {
874 $this->_packageXml['maintainers'] = $this->_options['maintainers'] = array();
875 }
876 return true;
877 }
878 }
879 if (!function_exists('file_get_contents')) {
880 /**
881 * @ignore
882 */
883 function file_get_contents($path, $use_include_path = null, $context = null)
884 {
885 $a = @file($path, $use_include_path, $context);
886 if (is_array($a)) {
887 return implode('', $a);
888 } else {
889 return false;
890 }
891 }
892 }
893 ?>

Documentation generated on Wed, 23 Jul 2003 17:29:44 -0400 by phpDocumentor 1.2.2