Updated PEAR and PEAR packages.
[timetracker.git] / WEB-INF / lib / pear / PEAR / PackageFile / Generator / v1.php
1 <?php
2 /**
3  * package.xml generation class, package.xml version 1.0
4  *
5  * PHP versions 4 and 5
6  *
7  * @category   pear
8  * @package    PEAR
9  * @author     Greg Beaver <cellog@php.net>
10  * @copyright  1997-2009 The Authors
11  * @license    http://opensource.org/licenses/bsd-license.php New BSD License
12  * @link       http://pear.php.net/package/PEAR
13  * @since      File available since Release 1.4.0a1
14  */
15 /**
16  * needed for PEAR_VALIDATE_* constants
17  */
18 require_once 'PEAR/Validate.php';
19 require_once 'System.php';
20 require_once 'PEAR/PackageFile/v2.php';
21 /**
22  * This class converts a PEAR_PackageFile_v1 object into any output format.
23  *
24  * Supported output formats include array, XML string, and a PEAR_PackageFile_v2
25  * object, for converting package.xml 1.0 into package.xml 2.0 with no sweat.
26  * @category   pear
27  * @package    PEAR
28  * @author     Greg Beaver <cellog@php.net>
29  * @copyright  1997-2009 The Authors
30  * @license    http://opensource.org/licenses/bsd-license.php New BSD License
31  * @version    Release: 1.10.1
32  * @link       http://pear.php.net/package/PEAR
33  * @since      Class available since Release 1.4.0a1
34  */
35 class PEAR_PackageFile_Generator_v1
36 {
37     /**
38      * @var PEAR_PackageFile_v1
39      */
40     var $_packagefile;
41     function __construct(&$packagefile)
42     {
43         $this->_packagefile = &$packagefile;
44     }
45
46     function getPackagerVersion()
47     {
48         return '1.10.1';
49     }
50
51     /**
52      * @param PEAR_Packager
53      * @param bool if true, a .tgz is written, otherwise a .tar is written
54      * @param string|null directory in which to save the .tgz
55      * @return string|PEAR_Error location of package or error object
56      */
57     function toTgz(&$packager, $compress = true, $where = null)
58     {
59         require_once 'Archive/Tar.php';
60         if ($where === null) {
61             if (!($where = System::mktemp(array('-d')))) {
62                 return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: mktemp failed');
63             }
64         } elseif (!@System::mkDir(array('-p', $where))) {
65             return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: "' . $where . '" could' .
66                 ' not be created');
67         }
68         if (file_exists($where . DIRECTORY_SEPARATOR . 'package.xml') &&
69               !is_file($where . DIRECTORY_SEPARATOR . 'package.xml')) {
70             return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: unable to save package.xml as' .
71                 ' "' . $where . DIRECTORY_SEPARATOR . 'package.xml"');
72         }
73         if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) {
74             return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: invalid package file');
75         }
76         $pkginfo = $this->_packagefile->getArray();
77         $ext = $compress ? '.tgz' : '.tar';
78         $pkgver = $pkginfo['package'] . '-' . $pkginfo['version'];
79         $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext;
80         if (file_exists(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext) &&
81               !is_file(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext)) {
82             return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: cannot create tgz file "' .
83                 getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext . '"');
84         }
85         if ($pkgfile = $this->_packagefile->getPackageFile()) {
86             $pkgdir = dirname(realpath($pkgfile));
87             $pkgfile = basename($pkgfile);
88         } else {
89             return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: package file object must ' .
90                 'be created from a real file');
91         }
92         // {{{ Create the package file list
93         $filelist = array();
94         $i = 0;
95
96         foreach ($this->_packagefile->getFilelist() as $fname => $atts) {
97             $file = $pkgdir . DIRECTORY_SEPARATOR . $fname;
98             if (!file_exists($file)) {
99                 return PEAR::raiseError("File does not exist: $fname");
100             } else {
101                 $filelist[$i++] = $file;
102                 if (!isset($atts['md5sum'])) {
103                     $this->_packagefile->setFileAttribute($fname, 'md5sum', md5_file($file));
104                 }
105                 $packager->log(2, "Adding file $fname");
106             }
107         }
108         // }}}
109         $packagexml = $this->toPackageFile($where, PEAR_VALIDATE_PACKAGING, 'package.xml', true);
110         if ($packagexml) {
111             $tar = new Archive_Tar($dest_package, $compress);
112             $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors
113             // ----- Creates with the package.xml file
114             $ok = $tar->createModify(array($packagexml), '', $where);
115             if (PEAR::isError($ok)) {
116                 return $ok;
117             } elseif (!$ok) {
118                 return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed');
119             }
120             // ----- Add the content of the package
121             if (!$tar->addModify($filelist, $pkgver, $pkgdir)) {
122                 return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed');
123             }
124             return $dest_package;
125         }
126     }
127
128     /**
129      * @param string|null directory to place the package.xml in, or null for a temporary dir
130      * @param int one of the PEAR_VALIDATE_* constants
131      * @param string name of the generated file
132      * @param bool if true, then no analysis will be performed on role="php" files
133      * @return string|PEAR_Error path to the created file on success
134      */
135     function toPackageFile($where = null, $state = PEAR_VALIDATE_NORMAL, $name = 'package.xml',
136                            $nofilechecking = false)
137     {
138         if (!$this->_packagefile->validate($state, $nofilechecking)) {
139             return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: invalid package.xml',
140                 null, null, null, $this->_packagefile->getValidationWarnings());
141         }
142         if ($where === null) {
143             if (!($where = System::mktemp(array('-d')))) {
144                 return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: mktemp failed');
145             }
146         } elseif (!@System::mkDir(array('-p', $where))) {
147             return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: "' . $where . '" could' .
148                 ' not be created');
149         }
150         $newpkgfile = $where . DIRECTORY_SEPARATOR . $name;
151         $np = @fopen($newpkgfile, 'wb');
152         if (!$np) {
153             return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: unable to save ' .
154                "$name as $newpkgfile");
155         }
156         fwrite($np, $this->toXml($state, true));
157         fclose($np);
158         return $newpkgfile;
159     }
160
161     /**
162      * fix both XML encoding to be UTF8, and replace standard XML entities < > " & '
163      *
164      * @param string $string
165      * @return string
166      * @access private
167      */
168     function _fixXmlEncoding($string)
169     {
170         return strtr($string, array(
171                                           '&'  => '&amp;',
172                                           '>'  => '&gt;',
173                                           '<'  => '&lt;',
174                                           '"'  => '&quot;',
175                                           '\'' => '&apos;' ));
176     }
177
178     /**
179      * Return an XML document based on the package info (as returned
180      * by the PEAR_Common::infoFrom* methods).
181      *
182      * @return string XML data
183      */
184     function toXml($state = PEAR_VALIDATE_NORMAL, $nofilevalidation = false)
185     {
186         $this->_packagefile->setDate(date('Y-m-d'));
187         if (!$this->_packagefile->validate($state, $nofilevalidation)) {
188             return false;
189         }
190         $pkginfo = $this->_packagefile->getArray();
191         static $maint_map = array(
192             "handle" => "user",
193             "name" => "name",
194             "email" => "email",
195             "role" => "role",
196             );
197         $ret = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
198         $ret .= "<!DOCTYPE package SYSTEM \"http://pear.php.net/dtd/package-1.0\">\n";
199         $ret .= "<package version=\"1.0\" packagerversion=\"1.10.1\">\n" .
200 " <name>$pkginfo[package]</name>";
201         if (isset($pkginfo['extends'])) {
202             $ret .= "\n<extends>$pkginfo[extends]</extends>";
203         }
204         $ret .=
205  "\n <summary>".$this->_fixXmlEncoding($pkginfo['summary'])."</summary>\n" .
206 " <description>".trim($this->_fixXmlEncoding($pkginfo['description']))."\n </description>\n" .
207 " <maintainers>\n";
208         foreach ($pkginfo['maintainers'] as $maint) {
209             $ret .= "  <maintainer>\n";
210             foreach ($maint_map as $idx => $elm) {
211                 $ret .= "   <$elm>";
212                 $ret .= $this->_fixXmlEncoding($maint[$idx]);
213                 $ret .= "</$elm>\n";
214             }
215             $ret .= "  </maintainer>\n";
216         }
217         $ret .= "  </maintainers>\n";
218         $ret .= $this->_makeReleaseXml($pkginfo, false, $state);
219         if (isset($pkginfo['changelog']) && count($pkginfo['changelog']) > 0) {
220             $ret .= " <changelog>\n";
221             foreach ($pkginfo['changelog'] as $oldrelease) {
222                 $ret .= $this->_makeReleaseXml($oldrelease, true);
223             }
224             $ret .= " </changelog>\n";
225         }
226         $ret .= "</package>\n";
227         return $ret;
228     }
229
230     // }}}
231     // {{{ _makeReleaseXml()
232
233     /**
234      * Generate part of an XML description with release information.
235      *
236      * @param array  $pkginfo    array with release information
237      * @param bool   $changelog  whether the result will be in a changelog element
238      *
239      * @return string XML data
240      *
241      * @access private
242      */
243     function _makeReleaseXml($pkginfo, $changelog = false, $state = PEAR_VALIDATE_NORMAL)
244     {
245         // XXX QUOTE ENTITIES IN PCDATA, OR EMBED IN CDATA BLOCKS!!
246         $indent = $changelog ? "  " : "";
247         $ret = "$indent <release>\n";
248         if (!empty($pkginfo['version'])) {
249             $ret .= "$indent  <version>$pkginfo[version]</version>\n";
250         }
251         if (!empty($pkginfo['release_date'])) {
252             $ret .= "$indent  <date>$pkginfo[release_date]</date>\n";
253         }
254         if (!empty($pkginfo['release_license'])) {
255             $ret .= "$indent  <license>$pkginfo[release_license]</license>\n";
256         }
257         if (!empty($pkginfo['release_state'])) {
258             $ret .= "$indent  <state>$pkginfo[release_state]</state>\n";
259         }
260         if (!empty($pkginfo['release_notes'])) {
261             $ret .= "$indent  <notes>".trim($this->_fixXmlEncoding($pkginfo['release_notes']))
262             ."\n$indent  </notes>\n";
263         }
264         if (!empty($pkginfo['release_warnings'])) {
265             $ret .= "$indent  <warnings>".$this->_fixXmlEncoding($pkginfo['release_warnings'])."</warnings>\n";
266         }
267         if (isset($pkginfo['release_deps']) && sizeof($pkginfo['release_deps']) > 0) {
268             $ret .= "$indent  <deps>\n";
269             foreach ($pkginfo['release_deps'] as $dep) {
270                 $ret .= "$indent   <dep type=\"$dep[type]\" rel=\"$dep[rel]\"";
271                 if (isset($dep['version'])) {
272                     $ret .= " version=\"$dep[version]\"";
273                 }
274                 if (isset($dep['optional'])) {
275                     $ret .= " optional=\"$dep[optional]\"";
276                 }
277                 if (isset($dep['name'])) {
278                     $ret .= ">$dep[name]</dep>\n";
279                 } else {
280                     $ret .= "/>\n";
281                 }
282             }
283             $ret .= "$indent  </deps>\n";
284         }
285         if (isset($pkginfo['configure_options'])) {
286             $ret .= "$indent  <configureoptions>\n";
287             foreach ($pkginfo['configure_options'] as $c) {
288                 $ret .= "$indent   <configureoption name=\"".
289                     $this->_fixXmlEncoding($c['name']) . "\"";
290                 if (isset($c['default'])) {
291                     $ret .= " default=\"" . $this->_fixXmlEncoding($c['default']) . "\"";
292                 }
293                 $ret .= " prompt=\"" . $this->_fixXmlEncoding($c['prompt']) . "\"";
294                 $ret .= "/>\n";
295             }
296             $ret .= "$indent  </configureoptions>\n";
297         }
298         if (isset($pkginfo['provides'])) {
299             foreach ($pkginfo['provides'] as $key => $what) {
300                 $ret .= "$indent  <provides type=\"$what[type]\" ";
301                 $ret .= "name=\"$what[name]\" ";
302                 if (isset($what['extends'])) {
303                     $ret .= "extends=\"$what[extends]\" ";
304                 }
305                 $ret .= "/>\n";
306             }
307         }
308         if (isset($pkginfo['filelist'])) {
309             $ret .= "$indent  <filelist>\n";
310             if ($state ^ PEAR_VALIDATE_PACKAGING) {
311                 $ret .= $this->recursiveXmlFilelist($pkginfo['filelist']);
312             } else {
313                 foreach ($pkginfo['filelist'] as $file => $fa) {
314                     if (!isset($fa['role'])) {
315                         $fa['role'] = '';
316                     }
317                     $ret .= "$indent   <file role=\"$fa[role]\"";
318                     if (isset($fa['baseinstalldir'])) {
319                         $ret .= ' baseinstalldir="' .
320                             $this->_fixXmlEncoding($fa['baseinstalldir']) . '"';
321                     }
322                     if (isset($fa['md5sum'])) {
323                         $ret .= " md5sum=\"$fa[md5sum]\"";
324                     }
325                     if (isset($fa['platform'])) {
326                         $ret .= " platform=\"$fa[platform]\"";
327                     }
328                     if (!empty($fa['install-as'])) {
329                         $ret .= ' install-as="' .
330                             $this->_fixXmlEncoding($fa['install-as']) . '"';
331                     }
332                     $ret .= ' name="' . $this->_fixXmlEncoding($file) . '"';
333                     if (empty($fa['replacements'])) {
334                         $ret .= "/>\n";
335                     } else {
336                         $ret .= ">\n";
337                         foreach ($fa['replacements'] as $r) {
338                             $ret .= "$indent    <replace";
339                             foreach ($r as $k => $v) {
340                                 $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"';
341                             }
342                             $ret .= "/>\n";
343                         }
344                         $ret .= "$indent   </file>\n";
345                     }
346                 }
347             }
348             $ret .= "$indent  </filelist>\n";
349         }
350         $ret .= "$indent </release>\n";
351         return $ret;
352     }
353
354     /**
355      * @param array
356      * @access protected
357      */
358     function recursiveXmlFilelist($list)
359     {
360         $this->_dirs = array();
361         foreach ($list as $file => $attributes) {
362             $this->_addDir($this->_dirs, explode('/', dirname($file)), $file, $attributes);
363         }
364         return $this->_formatDir($this->_dirs);
365     }
366
367     /**
368      * @param array
369      * @param array
370      * @param string|null
371      * @param array|null
372      * @access private
373      */
374     function _addDir(&$dirs, $dir, $file = null, $attributes = null)
375     {
376         if ($dir == array() || $dir == array('.')) {
377             $dirs['files'][basename($file)] = $attributes;
378             return;
379         }
380         $curdir = array_shift($dir);
381         if (!isset($dirs['dirs'][$curdir])) {
382             $dirs['dirs'][$curdir] = array();
383         }
384         $this->_addDir($dirs['dirs'][$curdir], $dir, $file, $attributes);
385     }
386
387     /**
388      * @param array
389      * @param string
390      * @param string
391      * @access private
392      */
393     function _formatDir($dirs, $indent = '', $curdir = '')
394     {
395         $ret = '';
396         if (!count($dirs)) {
397             return '';
398         }
399         if (isset($dirs['dirs'])) {
400             uksort($dirs['dirs'], 'strnatcasecmp');
401             foreach ($dirs['dirs'] as $dir => $contents) {
402                 $usedir = "$curdir/$dir";
403                 $ret .= "$indent   <dir name=\"$dir\">\n";
404                 $ret .= $this->_formatDir($contents, "$indent ", $usedir);
405                 $ret .= "$indent   </dir> <!-- $usedir -->\n";
406             }
407         }
408         if (isset($dirs['files'])) {
409             uksort($dirs['files'], 'strnatcasecmp');
410             foreach ($dirs['files'] as $file => $attribs) {
411                 $ret .= $this->_formatFile($file, $attribs, $indent);
412             }
413         }
414         return $ret;
415     }
416
417     /**
418      * @param string
419      * @param array
420      * @param string
421      * @access private
422      */
423     function _formatFile($file, $attributes, $indent)
424     {
425         $ret = "$indent   <file role=\"$attributes[role]\"";
426         if (isset($attributes['baseinstalldir'])) {
427             $ret .= ' baseinstalldir="' .
428                 $this->_fixXmlEncoding($attributes['baseinstalldir']) . '"';
429         }
430         if (isset($attributes['md5sum'])) {
431             $ret .= " md5sum=\"$attributes[md5sum]\"";
432         }
433         if (isset($attributes['platform'])) {
434             $ret .= " platform=\"$attributes[platform]\"";
435         }
436         if (!empty($attributes['install-as'])) {
437             $ret .= ' install-as="' .
438                 $this->_fixXmlEncoding($attributes['install-as']) . '"';
439         }
440         $ret .= ' name="' . $this->_fixXmlEncoding($file) . '"';
441         if (empty($attributes['replacements'])) {
442             $ret .= "/>\n";
443         } else {
444             $ret .= ">\n";
445             foreach ($attributes['replacements'] as $r) {
446                 $ret .= "$indent    <replace";
447                 foreach ($r as $k => $v) {
448                     $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"';
449                 }
450                 $ret .= "/>\n";
451             }
452             $ret .= "$indent   </file>\n";
453         }
454         return $ret;
455     }
456
457     // {{{ _unIndent()
458
459     /**
460      * Unindent given string (?)
461      *
462      * @param string $str The string that has to be unindented.
463      * @return string
464      * @access private
465      */
466     function _unIndent($str)
467     {
468         // remove leading newlines
469         $str = preg_replace('/^[\r\n]+/', '', $str);
470         // find whitespace at the beginning of the first line
471         $indent_len = strspn($str, " \t");
472         $indent = substr($str, 0, $indent_len);
473         $data = '';
474         // remove the same amount of whitespace from following lines
475         foreach (explode("\n", $str) as $line) {
476             if (substr($line, 0, $indent_len) == $indent) {
477                 $data .= substr($line, $indent_len) . "\n";
478             }
479         }
480         return $data;
481     }
482
483     /**
484      * @return array
485      */
486     function dependenciesToV2()
487     {
488         $arr = array();
489         $this->_convertDependencies2_0($arr);
490         return $arr['dependencies'];
491     }
492
493     /**
494      * Convert a package.xml version 1.0 into version 2.0
495      *
496      * Note that this does a basic conversion, to allow more advanced
497      * features like bundles and multiple releases
498      * @param string the classname to instantiate and return.  This must be
499      *               PEAR_PackageFile_v2 or a descendant
500      * @param boolean if true, only valid, deterministic package.xml 1.0 as defined by the
501      *                strictest parameters will be converted
502      * @return PEAR_PackageFile_v2|PEAR_Error
503      */
504     function &toV2($class = 'PEAR_PackageFile_v2', $strict = false)
505     {
506         if ($strict) {
507             if (!$this->_packagefile->validate()) {
508                 $a = PEAR::raiseError('invalid package.xml version 1.0 cannot be converted' .
509                     ' to version 2.0', null, null, null,
510                     $this->_packagefile->getValidationWarnings(true));
511                 return $a;
512             }
513         }
514
515         $arr = array(
516             'attribs' => array(
517                              'version' => '2.0',
518                              'xmlns' => 'http://pear.php.net/dtd/package-2.0',
519                              'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0',
520                              'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
521                              'xsi:schemaLocation' => "http://pear.php.net/dtd/tasks-1.0\n" .
522 "http://pear.php.net/dtd/tasks-1.0.xsd\n" .
523 "http://pear.php.net/dtd/package-2.0\n" .
524 'http://pear.php.net/dtd/package-2.0.xsd',
525                          ),
526             'name' => $this->_packagefile->getPackage(),
527             'channel' => 'pear.php.net',
528         );
529         $arr['summary'] = $this->_packagefile->getSummary();
530         $arr['description'] = $this->_packagefile->getDescription();
531         $maintainers = $this->_packagefile->getMaintainers();
532         foreach ($maintainers as $maintainer) {
533             if ($maintainer['role'] != 'lead') {
534                 continue;
535             }
536             $new = array(
537                 'name' => $maintainer['name'],
538                 'user' => $maintainer['handle'],
539                 'email' => $maintainer['email'],
540                 'active' => 'yes',
541             );
542             $arr['lead'][] = $new;
543         }
544
545         if (!isset($arr['lead'])) { // some people... you know?
546             $arr['lead'] = array(
547                 'name' => 'unknown',
548                 'user' => 'unknown',
549                 'email' => 'noleadmaintainer@example.com',
550                 'active' => 'no',
551             );
552         }
553
554         if (count($arr['lead']) == 1) {
555             $arr['lead'] = $arr['lead'][0];
556         }
557
558         foreach ($maintainers as $maintainer) {
559             if ($maintainer['role'] == 'lead') {
560                 continue;
561             }
562             $new = array(
563                 'name' => $maintainer['name'],
564                 'user' => $maintainer['handle'],
565                 'email' => $maintainer['email'],
566                 'active' => 'yes',
567             );
568             $arr[$maintainer['role']][] = $new;
569         }
570
571         if (isset($arr['developer']) && count($arr['developer']) == 1) {
572             $arr['developer'] = $arr['developer'][0];
573         }
574
575         if (isset($arr['contributor']) && count($arr['contributor']) == 1) {
576             $arr['contributor'] = $arr['contributor'][0];
577         }
578
579         if (isset($arr['helper']) && count($arr['helper']) == 1) {
580             $arr['helper'] = $arr['helper'][0];
581         }
582
583         $arr['date'] = $this->_packagefile->getDate();
584         $arr['version'] =
585             array(
586                 'release' => $this->_packagefile->getVersion(),
587                 'api' => $this->_packagefile->getVersion(),
588             );
589         $arr['stability'] =
590             array(
591                 'release' => $this->_packagefile->getState(),
592                 'api' => $this->_packagefile->getState(),
593             );
594         $licensemap =
595             array(
596                 'php' => 'http://www.php.net/license',
597                 'php license' => 'http://www.php.net/license',
598                 'lgpl' => 'http://www.gnu.org/copyleft/lesser.html',
599                 'bsd' => 'http://www.opensource.org/licenses/bsd-license.php',
600                 'bsd style' => 'http://www.opensource.org/licenses/bsd-license.php',
601                 'bsd-style' => 'http://www.opensource.org/licenses/bsd-license.php',
602                 'mit' => 'http://www.opensource.org/licenses/mit-license.php',
603                 'gpl' => 'http://www.gnu.org/copyleft/gpl.html',
604                 'apache' => 'http://www.opensource.org/licenses/apache2.0.php'
605             );
606
607         if (isset($licensemap[strtolower($this->_packagefile->getLicense())])) {
608             $arr['license'] = array(
609                 'attribs' => array('uri' =>
610                     $licensemap[strtolower($this->_packagefile->getLicense())]),
611                 '_content' => $this->_packagefile->getLicense()
612                 );
613         } else {
614             // don't use bogus uri
615             $arr['license'] = $this->_packagefile->getLicense();
616         }
617
618         $arr['notes'] = $this->_packagefile->getNotes();
619         $temp = array();
620         $arr['contents'] = $this->_convertFilelist2_0($temp);
621         $this->_convertDependencies2_0($arr);
622         $release = ($this->_packagefile->getConfigureOptions() || $this->_isExtension) ?
623             'extsrcrelease' : 'phprelease';
624         if ($release == 'extsrcrelease') {
625             $arr['channel'] = 'pecl.php.net';
626             $arr['providesextension'] = $arr['name']; // assumption
627         }
628
629         $arr[$release] = array();
630         if ($this->_packagefile->getConfigureOptions()) {
631             $arr[$release]['configureoption'] = $this->_packagefile->getConfigureOptions();
632             foreach ($arr[$release]['configureoption'] as $i => $opt) {
633                 $arr[$release]['configureoption'][$i] = array('attribs' => $opt);
634             }
635             if (count($arr[$release]['configureoption']) == 1) {
636                 $arr[$release]['configureoption'] = $arr[$release]['configureoption'][0];
637             }
638         }
639
640         $this->_convertRelease2_0($arr[$release], $temp);
641         if ($release == 'extsrcrelease' && count($arr[$release]) > 1) {
642             // multiple extsrcrelease tags added in PEAR 1.4.1
643             $arr['dependencies']['required']['pearinstaller']['min'] = '1.4.1';
644         }
645
646         if ($cl = $this->_packagefile->getChangelog()) {
647             foreach ($cl as $release) {
648                 $rel = array();
649                 $rel['version'] =
650                     array(
651                         'release' => $release['version'],
652                         'api' => $release['version'],
653                     );
654                 if (!isset($release['release_state'])) {
655                     $release['release_state'] = 'stable';
656                 }
657
658                 $rel['stability'] =
659                     array(
660                         'release' => $release['release_state'],
661                         'api' => $release['release_state'],
662                     );
663                 if (isset($release['release_date'])) {
664                     $rel['date'] = $release['release_date'];
665                 } else {
666                     $rel['date'] = date('Y-m-d');
667                 }
668
669                 if (isset($release['release_license'])) {
670                     if (isset($licensemap[strtolower($release['release_license'])])) {
671                         $uri = $licensemap[strtolower($release['release_license'])];
672                     } else {
673                         $uri = 'http://www.example.com';
674                     }
675                     $rel['license'] = array(
676                             'attribs' => array('uri' => $uri),
677                             '_content' => $release['release_license']
678                         );
679                 } else {
680                     $rel['license'] = $arr['license'];
681                 }
682
683                 if (!isset($release['release_notes'])) {
684                     $release['release_notes'] = 'no release notes';
685                 }
686
687                 $rel['notes'] = $release['release_notes'];
688                 $arr['changelog']['release'][] = $rel;
689             }
690         }
691
692         $ret = new $class;
693         $ret->setConfig($this->_packagefile->_config);
694         if (isset($this->_packagefile->_logger) && is_object($this->_packagefile->_logger)) {
695             $ret->setLogger($this->_packagefile->_logger);
696         }
697
698         $ret->fromArray($arr);
699         return $ret;
700     }
701
702     /**
703      * @param array
704      * @param bool
705      * @access private
706      */
707     function _convertDependencies2_0(&$release, $internal = false)
708     {
709         $peardep = array('pearinstaller' =>
710             array('min' => '1.4.0b1')); // this is a lot safer
711         $required = $optional = array();
712         $release['dependencies'] = array('required' => array());
713         if ($this->_packagefile->hasDeps()) {
714             foreach ($this->_packagefile->getDeps() as $dep) {
715                 if (!isset($dep['optional']) || $dep['optional'] == 'no') {
716                     $required[] = $dep;
717                 } else {
718                     $optional[] = $dep;
719                 }
720             }
721             foreach (array('required', 'optional') as $arr) {
722                 $deps = array();
723                 foreach ($$arr as $dep) {
724                     // organize deps by dependency type and name
725                     if (!isset($deps[$dep['type']])) {
726                         $deps[$dep['type']] = array();
727                     }
728                     if (isset($dep['name'])) {
729                         $deps[$dep['type']][$dep['name']][] = $dep;
730                     } else {
731                         $deps[$dep['type']][] = $dep;
732                     }
733                 }
734                 do {
735                     if (isset($deps['php'])) {
736                         $php = array();
737                         if (count($deps['php']) > 1) {
738                             $php = $this->_processPhpDeps($deps['php']);
739                         } else {
740                             if (!isset($deps['php'][0])) {
741                                 list($key, $blah) = each ($deps['php']); // stupid buggy versions
742                                 $deps['php'] = array($blah[0]);
743                             }
744                             $php = $this->_processDep($deps['php'][0]);
745                             if (!$php) {
746                                 break; // poor mans throw
747                             }
748                         }
749                         $release['dependencies'][$arr]['php'] = $php;
750                     }
751                 } while (false);
752                 do {
753                     if (isset($deps['pkg'])) {
754                         $pkg = array();
755                         $pkg = $this->_processMultipleDepsName($deps['pkg']);
756                         if (!$pkg) {
757                             break; // poor mans throw
758                         }
759                         $release['dependencies'][$arr]['package'] = $pkg;
760                     }
761                 } while (false);
762                 do {
763                     if (isset($deps['ext'])) {
764                         $pkg = array();
765                         $pkg = $this->_processMultipleDepsName($deps['ext']);
766                         $release['dependencies'][$arr]['extension'] = $pkg;
767                     }
768                 } while (false);
769                 // skip sapi - it's not supported so nobody will have used it
770                 // skip os - it's not supported in 1.0
771             }
772         }
773         if (isset($release['dependencies']['required'])) {
774             $release['dependencies']['required'] =
775                 array_merge($peardep, $release['dependencies']['required']);
776         } else {
777             $release['dependencies']['required'] = $peardep;
778         }
779         if (!isset($release['dependencies']['required']['php'])) {
780             $release['dependencies']['required']['php'] =
781                 array('min' => '4.0.0');
782         }
783         $order = array();
784         $bewm = $release['dependencies']['required'];
785         $order['php'] = $bewm['php'];
786         $order['pearinstaller'] = $bewm['pearinstaller'];
787         isset($bewm['package']) ? $order['package'] = $bewm['package'] :0;
788         isset($bewm['extension']) ? $order['extension'] = $bewm['extension'] :0;
789         $release['dependencies']['required'] = $order;
790     }
791
792     /**
793      * @param array
794      * @access private
795      */
796     function _convertFilelist2_0(&$package)
797     {
798         $ret = array('dir' =>
799                     array(
800                         'attribs' => array('name' => '/'),
801                         'file' => array()
802                         )
803                     );
804         $package['platform'] =
805         $package['install-as'] = array();
806         $this->_isExtension = false;
807         foreach ($this->_packagefile->getFilelist() as $name => $file) {
808             $file['name'] = $name;
809             if (isset($file['role']) && $file['role'] == 'src') {
810                 $this->_isExtension = true;
811             }
812             if (isset($file['replacements'])) {
813                 $repl = $file['replacements'];
814                 unset($file['replacements']);
815             } else {
816                 unset($repl);
817             }
818             if (isset($file['install-as'])) {
819                 $package['install-as'][$name] = $file['install-as'];
820                 unset($file['install-as']);
821             }
822             if (isset($file['platform'])) {
823                 $package['platform'][$name] = $file['platform'];
824                 unset($file['platform']);
825             }
826             $file = array('attribs' => $file);
827             if (isset($repl)) {
828                 foreach ($repl as $replace ) {
829                     $file['tasks:replace'][] = array('attribs' => $replace);
830                 }
831                 if (count($repl) == 1) {
832                     $file['tasks:replace'] = $file['tasks:replace'][0];
833                 }
834             }
835             $ret['dir']['file'][] = $file;
836         }
837         return $ret;
838     }
839
840     /**
841      * Post-process special files with install-as/platform attributes and
842      * make the release tag.
843      *
844      * This complex method follows this work-flow to create the release tags:
845      *
846      * <pre>
847      * - if any install-as/platform exist, create a generic release and fill it with
848      *   o <install as=..> tags for <file name=... install-as=...>
849      *   o <install as=..> tags for <file name=... platform=!... install-as=..>
850      *   o <ignore> tags for <file name=... platform=...>
851      *   o <ignore> tags for <file name=... platform=... install-as=..>
852      * - create a release for each platform encountered and fill with
853      *   o <install as..> tags for <file name=... install-as=...>
854      *   o <install as..> tags for <file name=... platform=this platform install-as=..>
855      *   o <install as..> tags for <file name=... platform=!other platform install-as=..>
856      *   o <ignore> tags for <file name=... platform=!this platform>
857      *   o <ignore> tags for <file name=... platform=other platform>
858      *   o <ignore> tags for <file name=... platform=other platform install-as=..>
859      *   o <ignore> tags for <file name=... platform=!this platform install-as=..>
860      * </pre>
861      *
862      * It does this by accessing the $package parameter, which contains an array with
863      * indices:
864      *
865      *  - platform: mapping of file => OS the file should be installed on
866      *  - install-as: mapping of file => installed name
867      *  - osmap: mapping of OS => list of files that should be installed
868      *    on that OS
869      *  - notosmap: mapping of OS => list of files that should not be
870      *    installed on that OS
871      *
872      * @param array
873      * @param array
874      * @access private
875      */
876     function _convertRelease2_0(&$release, $package)
877     {
878         //- if any install-as/platform exist, create a generic release and fill it with
879         if (count($package['platform']) || count($package['install-as'])) {
880             $generic = array();
881             $genericIgnore = array();
882             foreach ($package['install-as'] as $file => $as) {
883                 //o <install as=..> tags for <file name=... install-as=...>
884                 if (!isset($package['platform'][$file])) {
885                     $generic[] = $file;
886                     continue;
887                 }
888                 //o <install as=..> tags for <file name=... platform=!... install-as=..>
889                 if (isset($package['platform'][$file]) &&
890                       $package['platform'][$file]{0} == '!') {
891                     $generic[] = $file;
892                     continue;
893                 }
894                 //o <ignore> tags for <file name=... platform=... install-as=..>
895                 if (isset($package['platform'][$file]) &&
896                       $package['platform'][$file]{0} != '!') {
897                     $genericIgnore[] = $file;
898                     continue;
899                 }
900             }
901             foreach ($package['platform'] as $file => $platform) {
902                 if (isset($package['install-as'][$file])) {
903                     continue;
904                 }
905                 if ($platform{0} != '!') {
906                     //o <ignore> tags for <file name=... platform=...>
907                     $genericIgnore[] = $file;
908                 }
909             }
910             if (count($package['platform'])) {
911                 $oses = $notplatform = $platform = array();
912                 foreach ($package['platform'] as $file => $os) {
913                     // get a list of oses
914                     if ($os{0} == '!') {
915                         if (isset($oses[substr($os, 1)])) {
916                             continue;
917                         }
918                         $oses[substr($os, 1)] = count($oses);
919                     } else {
920                         if (isset($oses[$os])) {
921                             continue;
922                         }
923                         $oses[$os] = count($oses);
924                     }
925                 }
926                 //- create a release for each platform encountered and fill with
927                 foreach ($oses as $os => $releaseNum) {
928                     $release[$releaseNum]['installconditions']['os']['name'] = $os;
929                     $release[$releaseNum]['filelist'] = array('install' => array(),
930                         'ignore' => array());
931                     foreach ($package['install-as'] as $file => $as) {
932                         //o <install as=..> tags for <file name=... install-as=...>
933                         if (!isset($package['platform'][$file])) {
934                             $release[$releaseNum]['filelist']['install'][] =
935                                 array(
936                                     'attribs' => array(
937                                         'name' => $file,
938                                         'as' => $as,
939                                     ),
940                                 );
941                             continue;
942                         }
943                         //o <install as..> tags for
944                         //  <file name=... platform=this platform install-as=..>
945                         if (isset($package['platform'][$file]) &&
946                               $package['platform'][$file] == $os) {
947                             $release[$releaseNum]['filelist']['install'][] =
948                                 array(
949                                     'attribs' => array(
950                                         'name' => $file,
951                                         'as' => $as,
952                                     ),
953                                 );
954                             continue;
955                         }
956                         //o <install as..> tags for
957                         //  <file name=... platform=!other platform install-as=..>
958                         if (isset($package['platform'][$file]) &&
959                               $package['platform'][$file] != "!$os" &&
960                               $package['platform'][$file]{0} == '!') {
961                             $release[$releaseNum]['filelist']['install'][] =
962                                 array(
963                                     'attribs' => array(
964                                         'name' => $file,
965                                         'as' => $as,
966                                     ),
967                                 );
968                             continue;
969                         }
970                         //o <ignore> tags for
971                         //  <file name=... platform=!this platform install-as=..>
972                         if (isset($package['platform'][$file]) &&
973                               $package['platform'][$file] == "!$os") {
974                             $release[$releaseNum]['filelist']['ignore'][] =
975                                 array(
976                                     'attribs' => array(
977                                         'name' => $file,
978                                     ),
979                                 );
980                             continue;
981                         }
982                         //o <ignore> tags for
983                         //  <file name=... platform=other platform install-as=..>
984                         if (isset($package['platform'][$file]) &&
985                               $package['platform'][$file]{0} != '!' &&
986                               $package['platform'][$file] != $os) {
987                             $release[$releaseNum]['filelist']['ignore'][] =
988                                 array(
989                                     'attribs' => array(
990                                         'name' => $file,
991                                     ),
992                                 );
993                             continue;
994                         }
995                     }
996                     foreach ($package['platform'] as $file => $platform) {
997                         if (isset($package['install-as'][$file])) {
998                             continue;
999                         }
1000                         //o <ignore> tags for <file name=... platform=!this platform>
1001                         if ($platform == "!$os") {
1002                             $release[$releaseNum]['filelist']['ignore'][] =
1003                                 array(
1004                                     'attribs' => array(
1005                                         'name' => $file,
1006                                     ),
1007                                 );
1008                             continue;
1009                         }
1010                         //o <ignore> tags for <file name=... platform=other platform>
1011                         if ($platform{0} != '!' && $platform != $os) {
1012                             $release[$releaseNum]['filelist']['ignore'][] =
1013                                 array(
1014                                     'attribs' => array(
1015                                         'name' => $file,
1016                                     ),
1017                                 );
1018                         }
1019                     }
1020                     if (!count($release[$releaseNum]['filelist']['install'])) {
1021                         unset($release[$releaseNum]['filelist']['install']);
1022                     }
1023                     if (!count($release[$releaseNum]['filelist']['ignore'])) {
1024                         unset($release[$releaseNum]['filelist']['ignore']);
1025                     }
1026                 }
1027                 if (count($generic) || count($genericIgnore)) {
1028                     $release[count($oses)] = array();
1029                     if (count($generic)) {
1030                         foreach ($generic as $file) {
1031                             if (isset($package['install-as'][$file])) {
1032                                 $installas = $package['install-as'][$file];
1033                             } else {
1034                                 $installas = $file;
1035                             }
1036                             $release[count($oses)]['filelist']['install'][] =
1037                                 array(
1038                                     'attribs' => array(
1039                                         'name' => $file,
1040                                         'as' => $installas,
1041                                     )
1042                                 );
1043                         }
1044                     }
1045                     if (count($genericIgnore)) {
1046                         foreach ($genericIgnore as $file) {
1047                             $release[count($oses)]['filelist']['ignore'][] =
1048                                 array(
1049                                     'attribs' => array(
1050                                         'name' => $file,
1051                                     )
1052                                 );
1053                         }
1054                     }
1055                 }
1056                 // cleanup
1057                 foreach ($release as $i => $rel) {
1058                     if (isset($rel['filelist']['install']) &&
1059                           count($rel['filelist']['install']) == 1) {
1060                         $release[$i]['filelist']['install'] =
1061                             $release[$i]['filelist']['install'][0];
1062                     }
1063                     if (isset($rel['filelist']['ignore']) &&
1064                           count($rel['filelist']['ignore']) == 1) {
1065                         $release[$i]['filelist']['ignore'] =
1066                             $release[$i]['filelist']['ignore'][0];
1067                     }
1068                 }
1069                 if (count($release) == 1) {
1070                     $release = $release[0];
1071                 }
1072             } else {
1073                 // no platform atts, but some install-as atts
1074                 foreach ($package['install-as'] as $file => $value) {
1075                     $release['filelist']['install'][] =
1076                         array(
1077                             'attribs' => array(
1078                                 'name' => $file,
1079                                 'as' => $value
1080                             )
1081                         );
1082                 }
1083                 if (count($release['filelist']['install']) == 1) {
1084                     $release['filelist']['install'] = $release['filelist']['install'][0];
1085                 }
1086             }
1087         }
1088     }
1089
1090     /**
1091      * @param array
1092      * @return array
1093      * @access private
1094      */
1095     function _processDep($dep)
1096     {
1097         if ($dep['type'] == 'php') {
1098             if ($dep['rel'] == 'has') {
1099                 // come on - everyone has php!
1100                 return false;
1101             }
1102         }
1103         $php = array();
1104         if ($dep['type'] != 'php') {
1105             $php['name'] = $dep['name'];
1106             if ($dep['type'] == 'pkg') {
1107                 $php['channel'] = 'pear.php.net';
1108             }
1109         }
1110         switch ($dep['rel']) {
1111             case 'gt' :
1112                 $php['min'] = $dep['version'];
1113                 $php['exclude'] = $dep['version'];
1114             break;
1115             case 'ge' :
1116                 if (!isset($dep['version'])) {
1117                     if ($dep['type'] == 'php') {
1118                         if (isset($dep['name'])) {
1119                             $dep['version'] = $dep['name'];
1120                         }
1121                     }
1122                 }
1123                 $php['min'] = $dep['version'];
1124             break;
1125             case 'lt' :
1126                 $php['max'] = $dep['version'];
1127                 $php['exclude'] = $dep['version'];
1128             break;
1129             case 'le' :
1130                 $php['max'] = $dep['version'];
1131             break;
1132             case 'eq' :
1133                 $php['min'] = $dep['version'];
1134                 $php['max'] = $dep['version'];
1135             break;
1136             case 'ne' :
1137                 $php['exclude'] = $dep['version'];
1138             break;
1139             case 'not' :
1140                 $php['conflicts'] = 'yes';
1141             break;
1142         }
1143         return $php;
1144     }
1145
1146     /**
1147      * @param array
1148      * @return array
1149      */
1150     function _processPhpDeps($deps)
1151     {
1152         $test = array();
1153         foreach ($deps as $dep) {
1154             $test[] = $this->_processDep($dep);
1155         }
1156         $min = array();
1157         $max = array();
1158         foreach ($test as $dep) {
1159             if (!$dep) {
1160                 continue;
1161             }
1162             if (isset($dep['min'])) {
1163                 $min[$dep['min']] = count($min);
1164             }
1165             if (isset($dep['max'])) {
1166                 $max[$dep['max']] = count($max);
1167             }
1168         }
1169         if (count($min) > 0) {
1170             uksort($min, 'version_compare');
1171         }
1172         if (count($max) > 0) {
1173             uksort($max, 'version_compare');
1174         }
1175         if (count($min)) {
1176             // get the highest minimum
1177             $a = array_flip($min);
1178             $min = array_pop($a);
1179         } else {
1180             $min = false;
1181         }
1182         if (count($max)) {
1183             // get the lowest maximum
1184             $a = array_flip($max);
1185             $max = array_shift($a);
1186         } else {
1187             $max = false;
1188         }
1189         if ($min) {
1190             $php['min'] = $min;
1191         }
1192         if ($max) {
1193             $php['max'] = $max;
1194         }
1195         $exclude = array();
1196         foreach ($test as $dep) {
1197             if (!isset($dep['exclude'])) {
1198                 continue;
1199             }
1200             $exclude[] = $dep['exclude'];
1201         }
1202         if (count($exclude)) {
1203             $php['exclude'] = $exclude;
1204         }
1205         return $php;
1206     }
1207
1208     /**
1209      * process multiple dependencies that have a name, like package deps
1210      * @param array
1211      * @return array
1212      * @access private
1213      */
1214     function _processMultipleDepsName($deps)
1215     {
1216         $ret = $tests = array();
1217         foreach ($deps as $name => $dep) {
1218             foreach ($dep as $d) {
1219                 $tests[$name][] = $this->_processDep($d);
1220             }
1221         }
1222
1223         foreach ($tests as $name => $test) {
1224             $max = $min = $php = array();
1225             $php['name'] = $name;
1226             foreach ($test as $dep) {
1227                 if (!$dep) {
1228                     continue;
1229                 }
1230                 if (isset($dep['channel'])) {
1231                     $php['channel'] = 'pear.php.net';
1232                 }
1233                 if (isset($dep['conflicts']) && $dep['conflicts'] == 'yes') {
1234                     $php['conflicts'] = 'yes';
1235                 }
1236                 if (isset($dep['min'])) {
1237                     $min[$dep['min']] = count($min);
1238                 }
1239                 if (isset($dep['max'])) {
1240                     $max[$dep['max']] = count($max);
1241                 }
1242             }
1243             if (count($min) > 0) {
1244                 uksort($min, 'version_compare');
1245             }
1246             if (count($max) > 0) {
1247                 uksort($max, 'version_compare');
1248             }
1249             if (count($min)) {
1250                 // get the highest minimum
1251                 $a = array_flip($min);
1252                 $min = array_pop($a);
1253             } else {
1254                 $min = false;
1255             }
1256             if (count($max)) {
1257                 // get the lowest maximum
1258                 $a = array_flip($max);
1259                 $max = array_shift($a);
1260             } else {
1261                 $max = false;
1262             }
1263             if ($min) {
1264                 $php['min'] = $min;
1265             }
1266             if ($max) {
1267                 $php['max'] = $max;
1268             }
1269             $exclude = array();
1270             foreach ($test as $dep) {
1271                 if (!isset($dep['exclude'])) {
1272                     continue;
1273                 }
1274                 $exclude[] = $dep['exclude'];
1275             }
1276             if (count($exclude)) {
1277                 $php['exclude'] = $exclude;
1278             }
1279             $ret[] = $php;
1280         }
1281         return $ret;
1282     }
1283 }
1284 ?>