3 * PEAR_Command_Package (package, package-validate, cvsdiff, cvstag, package-dependencies,
4 * sign, makerpm, convert commands)
10 * @author Stig Bakken <ssb@php.net>
11 * @author Martin Jansen <mj@php.net>
12 * @author Greg Beaver <cellog@php.net>
13 * @copyright 1997-2009 The Authors
14 * @license http://opensource.org/licenses/bsd-license.php New BSD License
15 * @link http://pear.php.net/package/PEAR
16 * @since File available since Release 0.1
22 require_once 'PEAR/Command/Common.php';
25 * PEAR commands for login/logout
29 * @author Stig Bakken <ssb@php.net>
30 * @author Martin Jansen <mj@php.net>
31 * @author Greg Beaver <cellog@php.net>
32 * @copyright 1997-2009 The Authors
33 * @license http://opensource.org/licenses/bsd-license.php New BSD License
34 * @version Release: @package_version@
35 * @link http://pear.php.net/package/PEAR
36 * @since Class available since Release 0.1
39 class PEAR_Command_Package extends PEAR_Command_Common
41 var $commands = array(
43 'summary' => 'Build Package',
44 'function' => 'doPackage',
47 'nocompress' => array(
49 'doc' => 'Do not gzip the package file'
53 'doc' => 'Print the name of the packaged file.',
56 'doc' => '[descfile] [descfile2]
57 Creates a PEAR package from its description file (usually called
58 package.xml). If a second packagefile is passed in, then
59 the packager will check to make sure that one is a package.xml
60 version 1.0, and the other is a package.xml version 2.0. The
61 package.xml version 1.0 will be saved as "package.xml" in the archive,
62 and the other as "package2.xml" in the archive"
65 'package-validate' => array(
66 'summary' => 'Validate Package Consistency',
67 'function' => 'doPackageValidate',
74 'summary' => 'Run a "cvs diff" for all files in a package',
75 'function' => 'doCvsDiff',
82 'reallyquiet' => array(
84 'doc' => 'Be really quiet',
88 'doc' => 'Diff against revision of DATE',
93 'doc' => 'Diff against tag for package release REL',
98 'doc' => 'Diff against revision REV',
103 'doc' => 'Generate context diff',
107 'doc' => 'Generate unified diff',
109 'ignore-case' => array(
111 'doc' => 'Ignore case, consider upper- and lower-case letters equivalent',
113 'ignore-whitespace' => array(
115 'doc' => 'Ignore changes in amount of white space',
117 'ignore-blank-lines' => array(
119 'doc' => 'Ignore changes that insert or delete blank lines',
122 'doc' => 'Report only whether the files differ, no details',
126 'doc' => 'Don\'t do anything, just pretend',
129 'doc' => '<package.xml>
130 Compares all the files in a package. Without any options, this
131 command will compare the current code with the last checked-in code.
132 Using the -r or -R option you may compare the current code with that
133 of a specific release.
137 'summary' => 'Set SVN Release Tag',
138 'function' => 'doSvnTag',
147 'doc' => 'Move (slide) tag if it exists',
151 'doc' => 'Remove tag',
155 'doc' => 'Don\'t do anything, just pretend',
158 'doc' => '<package.xml> [files...]
159 Sets a SVN tag on all files in a package. Use this command after you have
160 packaged a distribution tarball with the "package" command to tag what
161 revisions of what files were in that release. If need to fix something
162 after running svntag once, but before the tarball is released to the public,
163 use the "slide" option to move the release tag.
165 to include files (such as a second package.xml, or tests not included in the
166 release), pass them as additional parameters.
170 'summary' => 'Set CVS Release Tag',
171 'function' => 'doCvsTag',
178 'reallyquiet' => array(
180 'doc' => 'Be really quiet',
184 'doc' => 'Move (slide) tag if it exists',
188 'doc' => 'Remove tag',
192 'doc' => 'Don\'t do anything, just pretend',
195 'doc' => '<package.xml> [files...]
196 Sets a CVS tag on all files in a package. Use this command after you have
197 packaged a distribution tarball with the "package" command to tag what
198 revisions of what files were in that release. If need to fix something
199 after running cvstag once, but before the tarball is released to the public,
200 use the "slide" option to move the release tag.
202 to include files (such as a second package.xml, or tests not included in the
203 release), pass them as additional parameters.
206 'package-dependencies' => array(
207 'summary' => 'Show package dependencies',
208 'function' => 'doPackageDependencies',
210 'options' => array(),
211 'doc' => '<package-file> or <package.xml> or <install-package-name>
212 List all dependencies the package has.
213 Can take a tgz / tar file, package.xml or a package name of an installed package.'
216 'summary' => 'Sign a package distribution file',
217 'function' => 'doSign',
222 'doc' => 'Display GnuPG output',
225 'doc' => '<package-file>
226 Signs a package distribution (.tar or .tgz) file with GnuPG.',
229 'summary' => 'Builds an RPM spec file from a PEAR package',
230 'function' => 'doMakeRPM',
233 'spec-template' => array(
236 'doc' => 'Use FILE as RPM spec file template'
238 'rpm-pkgname' => array(
241 'doc' => 'Use FORMAT as format string for RPM package name, %s is replaced
242 by the PEAR package name, defaults to "PEAR::%s".',
245 'doc' => '<package-file>
247 Creates an RPM .spec file for wrapping a PEAR package inside an RPM
248 package. Intended to be used from the SPECS directory, with the PEAR
249 package tarball in the SOURCES directory:
251 $ pear makerpm ../SOURCES/Net_Socket-1.0.tgz
252 Wrote RPM spec file PEAR::Net_Geo-1.0.spec
253 $ rpm -bb PEAR::Net_Socket-1.0.spec
255 Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
259 'summary' => 'Convert a package.xml 1.0 to package.xml 2.0 format',
260 'function' => 'doConvert',
265 'doc' => 'do not beautify the filelist.',
268 'doc' => '[descfile] [descfile2]
269 Converts a package.xml in 1.0 format into a package.xml
270 in 2.0 format. The new file will be named package2.xml by default,
271 and package.xml will be used as the old file by default.
272 This is not the most intelligent conversion, and should only be
273 used for automated conversion or learning the format.
281 * PEAR_Command_Package constructor.
285 function __construct(&$ui, &$config)
287 parent::__construct($ui, $config);
290 function _displayValidationResults($err, $warn, $strict = false)
292 foreach ($err as $e) {
293 $this->output .= "Error: $e\n";
295 foreach ($warn as $w) {
296 $this->output .= "Warning: $w\n";
298 $this->output .= sprintf('Validation: %d error(s), %d warning(s)'."\n",
299 sizeof($err), sizeof($warn));
300 if ($strict && count($err) > 0) {
301 $this->output .= "Fix these errors and try again.";
307 function &getPackager()
309 if (!class_exists('PEAR_Packager')) {
310 require_once 'PEAR/Packager.php';
312 $a = new PEAR_Packager;
316 function &getPackageFile($config, $debug = false)
318 if (!class_exists('PEAR_Common')) {
319 require_once 'PEAR/Common.php';
321 if (!class_exists('PEAR_PackageFile')) {
322 require_once 'PEAR/PackageFile.php';
324 $a = new PEAR_PackageFile($config, $debug);
325 $common = new PEAR_Common;
326 $common->ui = $this->ui;
327 $a->setLogger($common);
331 function doPackage($command, $options, $params)
334 $pkginfofile = isset($params[0]) ? $params[0] : 'package.xml';
335 $pkg2 = isset($params[1]) ? $params[1] : null;
336 if (!$pkg2 && !isset($params[0]) && file_exists('package2.xml')) {
337 $pkg2 = 'package2.xml';
340 $packager = &$this->getPackager();
341 $compress = empty($options['nocompress']) ? true : false;
342 $result = $packager->package($pkginfofile, $compress, $pkg2);
343 if (PEAR::isError($result)) {
344 return $this->raiseError($result);
347 // Don't want output, only the package file name just created
348 if (isset($options['showname'])) {
349 $this->output = $result;
353 $this->ui->outputData($this->output, $command);
359 function doPackageValidate($command, $options, $params)
362 if (count($params) < 1) {
363 $params[0] = 'package.xml';
366 $obj = &$this->getPackageFile($this->config, $this->_debug);
368 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
369 $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL);
370 if (PEAR::isError($info)) {
371 $info = $obj->fromPackageFile($params[0], PEAR_VALIDATE_NORMAL);
373 $archive = $info->getArchiveFile();
374 $tar = new Archive_Tar($archive);
375 $tar->extract(dirname($info->getPackageFile()));
376 $info->setPackageFile(dirname($info->getPackageFile()) . DIRECTORY_SEPARATOR .
377 $info->getPackage() . '-' . $info->getVersion() . DIRECTORY_SEPARATOR .
378 basename($info->getPackageFile()));
381 PEAR::staticPopErrorHandling();
382 if (PEAR::isError($info)) {
383 return $this->raiseError($info);
387 if ($info->getPackagexmlVersion() == '2.0') {
388 if ($valid = $info->validate(PEAR_VALIDATE_NORMAL)) {
389 $info->flattenFileList();
390 $valid = $info->validate(PEAR_VALIDATE_PACKAGING);
393 $valid = $info->validate(PEAR_VALIDATE_PACKAGING);
396 $err = $warn = array();
397 if ($errors = $info->getValidationWarnings()) {
398 foreach ($errors as $error) {
399 if ($error['level'] == 'warning') {
400 $warn[] = $error['message'];
402 $err[] = $error['message'];
407 $this->_displayValidationResults($err, $warn);
408 $this->ui->outputData($this->output, $command);
412 function doSvnTag($command, $options, $params)
416 if (count($params) < 1) {
417 $help = $this->getHelp($command);
418 return $this->raiseError("$command: missing parameter: $help[0]");
421 $packageFile = realpath($params[0]);
422 $dir = dirname($packageFile);
423 $dir = substr($dir, strrpos($dir, DIRECTORY_SEPARATOR) + 1);
424 $obj = &$this->getPackageFile($this->config, $this->_debug);
425 $info = $obj->fromAnyFile($packageFile, PEAR_VALIDATE_NORMAL);
426 if (PEAR::isError($info)) {
427 return $this->raiseError($info);
430 $err = $warn = array();
431 if (!$info->validate()) {
432 foreach ($info->getValidationWarnings() as $error) {
433 if ($error['level'] == 'warning') {
434 $warn[] = $error['message'];
436 $err[] = $error['message'];
441 if (!$this->_displayValidationResults($err, $warn, true)) {
442 $this->ui->outputData($this->output, $command);
443 return $this->raiseError('SVN tag failed');
446 $version = $info->getVersion();
447 $package = $info->getName();
448 $svntag = "$package-$version";
450 if (isset($options['delete'])) {
451 return $this->_svnRemoveTag($version, $package, $svntag, $packageFile, $options);
454 $path = $this->_svnFindPath($packageFile);
456 // Check if there are any modified files
457 $fp = popen('svn st --xml ' . dirname($packageFile), "r");
459 while ($line = fgets($fp, 1024)) {
460 $out .= rtrim($line)."\n";
464 if (!isset($options['quiet']) && strpos($out, 'item="modified"')) {
465 $params = array(array(
466 'name' => 'modified',
469 'prompt' => 'You have files in your SVN checkout (' . $path['from'] . ') that have been modified but not committed, do you still want to tag ' . $version . '?',
471 $answers = $this->ui->confirmDialog($params);
473 if (!in_array($answers['modified'], array('y', 'yes', 'on', '1'))) {
478 if (isset($options['slide'])) {
479 $this->_svnRemoveTag($version, $package, $svntag, $packageFile, $options);
482 // Check if tag already exists
483 $releaseTag = $path['local']['base'] . 'tags' . DIRECTORY_SEPARATOR . $svntag;
484 $existsCommand = 'svn ls ' . $path['base'] . 'tags/';
486 $fp = popen($existsCommand, "r");
488 while ($line = fgets($fp, 1024)) {
489 $out .= rtrim($line)."\n";
493 if (in_array($svntag . DIRECTORY_SEPARATOR, explode("\n", $out))) {
494 $this->ui->outputData($this->output, $command);
495 return $this->raiseError('SVN tag ' . $svntag . ' for ' . $package . ' already exists.');
496 } elseif (file_exists($path['local']['base'] . 'tags') === false) {
497 return $this->raiseError('Can not locate the tags directory at ' . $path['local']['base'] . 'tags');
498 } elseif (is_writeable($path['local']['base'] . 'tags') === false) {
499 return $this->raiseError('Can not write to the tag directory at ' . $path['local']['base'] . 'tags');
501 $makeCommand = 'svn mkdir ' . $releaseTag;
502 $this->output .= "+ $makeCommand\n";
503 if (empty($options['dry-run'])) {
504 // We need to create the tag dir.
505 $fp = popen($makeCommand, "r");
507 while ($line = fgets($fp, 1024)) {
508 $out .= rtrim($line)."\n";
511 $this->output .= "$out\n";
516 if (isset($options['quiet'])) {
520 $command .= ' copy --parents ';
522 $dir = dirname($packageFile);
523 $dir = substr($dir, strrpos($dir, DIRECTORY_SEPARATOR) + 1);
524 $files = array_keys($info->getFilelist());
525 if (!in_array(basename($packageFile), $files)) {
526 $files[] = basename($packageFile);
529 array_shift($params);
530 if (count($params)) {
531 // add in additional files to be tagged (package files and such)
532 $files = array_merge($files, $params);
536 foreach ($files as $file) {
537 if (!file_exists($file)) {
538 $file = $dir . DIRECTORY_SEPARATOR . $file;
540 $commands[] = $command . ' ' . escapeshellarg($file) . ' ' .
541 escapeshellarg($releaseTag . DIRECTORY_SEPARATOR . $file);
544 $this->output .= implode("\n", $commands) . "\n";
545 if (empty($options['dry-run'])) {
546 foreach ($commands as $command) {
547 $fp = popen($command, "r");
548 while ($line = fgets($fp, 1024)) {
549 $this->output .= rtrim($line)."\n";
555 $command = 'svn ci -m "Tagging the ' . $version . ' release" ' . $releaseTag . "\n";
556 $this->output .= "+ $command\n";
557 if (empty($options['dry-run'])) {
558 $fp = popen($command, "r");
559 while ($line = fgets($fp, 1024)) {
560 $this->output .= rtrim($line)."\n";
565 $this->ui->outputData($this->output, $_cmd);
569 function _svnFindPath($file)
572 $command = "svn info --xml $file";
573 $fp = popen($command, "r");
574 while ($line = fgets($fp, 1024)) {
575 $xml .= rtrim($line)."\n";
578 $url_tag = strpos($xml, '<url>');
579 $url = substr($xml, $url_tag + 5, strpos($xml, '</url>', $url_tag + 5) - ($url_tag + 5));
582 $path['from'] = substr($url, 0, strrpos($url, '/'));
583 $path['base'] = substr($path['from'], 0, strrpos($path['from'], '/') + 1);
585 // Figure out the local paths - see http://pear.php.net/bugs/17463
586 $pos = strpos($file, DIRECTORY_SEPARATOR . 'trunk' . DIRECTORY_SEPARATOR);
587 if ($pos === false) {
588 $pos = strpos($file, DIRECTORY_SEPARATOR . 'branches' . DIRECTORY_SEPARATOR);
590 $path['local']['base'] = substr($file, 0, $pos + 1);
595 function _svnRemoveTag($version, $package, $tag, $packageFile, $options)
599 if (isset($options['quiet'])) {
603 $command .= ' remove';
604 $command .= ' -m "Removing tag for the ' . $version . ' release."';
606 $path = $this->_svnFindPath($packageFile);
607 $command .= ' ' . $path['base'] . 'tags/' . $tag;
610 if ($this->config->get('verbose') > 1) {
611 $this->output .= "+ $command\n";
614 $this->output .= "+ $command\n";
615 if (empty($options['dry-run'])) {
616 $fp = popen($command, "r");
617 while ($line = fgets($fp, 1024)) {
618 $this->output .= rtrim($line)."\n";
623 $this->ui->outputData($this->output, $command);
627 function doCvsTag($command, $options, $params)
631 if (count($params) < 1) {
632 $help = $this->getHelp($command);
633 return $this->raiseError("$command: missing parameter: $help[0]");
636 $packageFile = realpath($params[0]);
637 $obj = &$this->getPackageFile($this->config, $this->_debug);
638 $info = $obj->fromAnyFile($packageFile, PEAR_VALIDATE_NORMAL);
639 if (PEAR::isError($info)) {
640 return $this->raiseError($info);
643 $err = $warn = array();
644 if (!$info->validate()) {
645 foreach ($info->getValidationWarnings() as $error) {
646 if ($error['level'] == 'warning') {
647 $warn[] = $error['message'];
649 $err[] = $error['message'];
654 if (!$this->_displayValidationResults($err, $warn, true)) {
655 $this->ui->outputData($this->output, $command);
656 return $this->raiseError('CVS tag failed');
659 $version = $info->getVersion();
660 $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $version);
661 $cvstag = "RELEASE_$cvsversion";
662 $files = array_keys($info->getFilelist());
664 if (isset($options['quiet'])) {
668 if (isset($options['reallyquiet'])) {
673 if (isset($options['slide'])) {
677 if (isset($options['delete'])) {
681 $command .= ' ' . $cvstag . ' ' . escapeshellarg($params[0]);
682 array_shift($params);
683 if (count($params)) {
684 // add in additional files to be tagged
685 $files = array_merge($files, $params);
688 $dir = dirname($packageFile);
689 $dir = substr($dir, strrpos($dir, '/') + 1);
690 foreach ($files as $file) {
691 if (!file_exists($file)) {
692 $file = $dir . DIRECTORY_SEPARATOR . $file;
694 $command .= ' ' . escapeshellarg($file);
697 if ($this->config->get('verbose') > 1) {
698 $this->output .= "+ $command\n";
701 $this->output .= "+ $command\n";
702 if (empty($options['dry-run'])) {
703 $fp = popen($command, "r");
704 while ($line = fgets($fp, 1024)) {
705 $this->output .= rtrim($line)."\n";
710 $this->ui->outputData($this->output, $_cmd);
714 function doCvsDiff($command, $options, $params)
717 if (sizeof($params) < 1) {
718 $help = $this->getHelp($command);
719 return $this->raiseError("$command: missing parameter: $help[0]");
722 $file = realpath($params[0]);
723 $obj = &$this->getPackageFile($this->config, $this->_debug);
724 $info = $obj->fromAnyFile($file, PEAR_VALIDATE_NORMAL);
725 if (PEAR::isError($info)) {
726 return $this->raiseError($info);
729 $err = $warn = array();
730 if (!$info->validate()) {
731 foreach ($info->getValidationWarnings() as $error) {
732 if ($error['level'] == 'warning') {
733 $warn[] = $error['message'];
735 $err[] = $error['message'];
740 if (!$this->_displayValidationResults($err, $warn, true)) {
741 $this->ui->outputData($this->output, $command);
742 return $this->raiseError('CVS diff failed');
745 $info1 = $info->getFilelist();
748 if (isset($options['quiet'])) {
750 unset($options['quiet']);
753 if (isset($options['reallyquiet'])) {
755 unset($options['reallyquiet']);
758 if (isset($options['release'])) {
759 $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $options['release']);
760 $cvstag = "RELEASE_$cvsversion";
761 $options['revision'] = $cvstag;
762 unset($options['release']);
766 if (isset($options['dry-run'])) {
768 unset($options['dry-run']);
772 // the rest of the options are passed right on to "cvs diff"
773 foreach ($options as $option => $optarg) {
774 $arg = $short = false;
775 if (isset($this->commands[$command]['options'][$option])) {
776 $arg = $this->commands[$command]['options'][$option]['arg'];
777 $short = $this->commands[$command]['options'][$option]['shortopt'];
779 $cmd .= $short ? " -$short" : " --$option";
780 if ($arg && $optarg) {
781 $cmd .= ($short ? '' : '=') . escapeshellarg($optarg);
785 foreach ($files as $file) {
786 $cmd .= ' ' . escapeshellarg($file['name']);
789 if ($this->config->get('verbose') > 1) {
790 $this->output .= "+ $cmd\n";
794 $fp = popen($cmd, "r");
795 while ($line = fgets($fp, 1024)) {
796 $this->output .= rtrim($line)."\n";
801 $this->ui->outputData($this->output, $command);
805 function doPackageDependencies($command, $options, $params)
807 // $params[0] -> the PEAR package to list its information
808 if (count($params) !== 1) {
809 return $this->raiseError("bad parameter(s), try \"help $command\"");
812 $obj = &$this->getPackageFile($this->config, $this->_debug);
813 if (is_file($params[0]) || strpos($params[0], '.xml') > 0) {
814 $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
816 $reg = $this->config->getRegistry();
817 $info = $obj->fromArray($reg->packageInfo($params[0]));
820 if (PEAR::isError($info)) {
821 return $this->raiseError($info);
824 $deps = $info->getDeps();
825 if (is_array($deps)) {
826 if ($info->getPackagexmlVersion() == '1.0') {
828 'caption' => 'Dependencies for pear/' . $info->getPackage(),
830 'headline' => array("Required?", "Type", "Name", "Relation", "Version"),
833 foreach ($deps as $d) {
834 if (isset($d['optional'])) {
835 if ($d['optional'] == 'yes') {
844 if (isset($this->_deps_rel_trans[$d['rel']])) {
845 $rel = $this->_deps_rel_trans[$d['rel']];
850 if (isset($this->_deps_type_trans[$d['type']])) {
851 $type = ucfirst($this->_deps_type_trans[$d['type']]);
856 if (isset($d['name'])) {
862 if (isset($d['version'])) {
863 $version = $d['version'];
868 $data['data'][] = array($req, $type, $name, $rel, $version);
870 } else { // package.xml 2.0 dependencies display
871 require_once 'PEAR/Dependency2.php';
872 $deps = $info->getDependencies();
873 $reg = &$this->config->getRegistry();
874 if (is_array($deps)) {
875 $d = new PEAR_Dependency2($this->config, array(), '');
877 'caption' => 'Dependencies for ' . $info->getPackage(),
879 'headline' => array("Required?", "Type", "Name", 'Versioning', 'Group'),
881 foreach ($deps as $type => $subd) {
882 $req = ($type == 'required') ? 'Yes' : 'No';
883 if ($type == 'group' && isset($subd['attribs']['name'])) {
884 $group = $subd['attribs']['name'];
889 if (!isset($subd[0])) {
890 $subd = array($subd);
893 foreach ($subd as $groupa) {
894 foreach ($groupa as $deptype => $depinfo) {
895 if ($deptype == 'attribs') {
899 if ($deptype == 'pearinstaller') {
900 $deptype = 'pear Installer';
903 if (!isset($depinfo[0])) {
904 $depinfo = array($depinfo);
907 foreach ($depinfo as $inf) {
909 if (isset($inf['channel'])) {
910 $alias = $reg->channelAlias($inf['channel']);
912 $alias = '(channel?) ' .$inf['channel'];
914 $name = $alias . '/';
917 if (isset($inf['name'])) {
918 $name .= $inf['name'];
919 } elseif (isset($inf['pattern'])) {
920 $name .= $inf['pattern'];
925 if (isset($inf['uri'])) {
926 $name .= ' [' . $inf['uri'] . ']';
929 if (isset($inf['conflicts'])) {
932 $ver = $d->_getExtraString($inf);
935 $data['data'][] = array($req, ucfirst($deptype), $name,
944 $this->ui->outputData($data, $command);
949 $this->ui->outputData("This package does not have any dependencies.", $command);
952 function doSign($command, $options, $params)
954 // should move most of this code into PEAR_Packager
955 // so it'll be easy to implement "pear package --sign"
956 if (count($params) !== 1) {
957 return $this->raiseError("bad parameter(s), try \"help $command\"");
960 require_once 'System.php';
961 require_once 'Archive/Tar.php';
963 if (!file_exists($params[0])) {
964 return $this->raiseError("file does not exist: $params[0]");
967 $obj = $this->getPackageFile($this->config, $this->_debug);
968 $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL);
969 if (PEAR::isError($info)) {
970 return $this->raiseError($info);
973 $tar = new Archive_Tar($params[0]);
975 $tmpdir = $this->config->get('temp_dir');
976 $tmpdir = System::mktemp(' -t "' . $tmpdir . '" -d pearsign');
977 if (!$tar->extractList('package2.xml package.xml package.sig', $tmpdir)) {
978 return $this->raiseError("failed to extract tar file");
981 if (file_exists("$tmpdir/package.sig")) {
982 return $this->raiseError("package already signed");
985 $packagexml = 'package.xml';
986 if (file_exists("$tmpdir/package2.xml")) {
987 $packagexml = 'package2.xml';
990 if (file_exists("$tmpdir/package.sig")) {
991 unlink("$tmpdir/package.sig");
994 if (!file_exists("$tmpdir/$packagexml")) {
995 return $this->raiseError("Extracted file $tmpdir/$packagexml not found.");
998 $input = $this->ui->userDialog($command,
999 array('GnuPG Passphrase'),
1001 if (!isset($input[0])) {
1002 //use empty passphrase
1006 $devnull = (isset($options['verbose'])) ? '' : ' 2>/dev/null';
1007 $gpg = popen("gpg --batch --passphrase-fd 0 --armor --detach-sign --output $tmpdir/package.sig $tmpdir/$packagexml" . $devnull, "w");
1009 return $this->raiseError("gpg command failed");
1012 fwrite($gpg, "$input[0]\n");
1013 if (pclose($gpg) || !file_exists("$tmpdir/package.sig")) {
1014 return $this->raiseError("gpg sign failed");
1017 if (!$tar->addModify("$tmpdir/package.sig", '', $tmpdir)) {
1018 return $this->raiseError('failed adding signature to file');
1021 $this->ui->outputData("Package signed.", $command);
1026 * For unit testing purposes
1028 function &getInstaller(&$ui)
1030 if (!class_exists('PEAR_Installer')) {
1031 require_once 'PEAR/Installer.php';
1033 $a = new PEAR_Installer($ui);
1038 * For unit testing purposes
1040 function &getCommandPackaging(&$ui, &$config)
1042 if (!class_exists('PEAR_Command_Packaging')) {
1043 if ($fp = @fopen('PEAR/Command/Packaging.php', 'r', true)) {
1045 include_once 'PEAR/Command/Packaging.php';
1049 if (class_exists('PEAR_Command_Packaging')) {
1050 $a = new PEAR_Command_Packaging($ui, $config);
1058 function doMakeRPM($command, $options, $params)
1061 // Check to see if PEAR_Command_Packaging is installed, and
1062 // transparently switch to use the "make-rpm-spec" command from it
1063 // instead, if it does. Otherwise, continue to use the old version
1064 // of "makerpm" supplied with this package (PEAR).
1065 $packaging_cmd = $this->getCommandPackaging($this->ui, $this->config);
1066 if ($packaging_cmd !== null) {
1067 $this->ui->outputData('PEAR_Command_Packaging is installed; using '.
1068 'newer "make-rpm-spec" command instead');
1069 return $packaging_cmd->run('make-rpm-spec', $options, $params);
1072 $this->ui->outputData('WARNING: "pear makerpm" is no longer available; an '.
1073 'improved version is available via "pear make-rpm-spec", which '.
1074 'is available by installing PEAR_Command_Packaging');
1078 function doConvert($command, $options, $params)
1080 $packagexml = isset($params[0]) ? $params[0] : 'package.xml';
1081 $newpackagexml = isset($params[1]) ? $params[1] : dirname($packagexml) .
1082 DIRECTORY_SEPARATOR . 'package2.xml';
1083 $pkg = &$this->getPackageFile($this->config, $this->_debug);
1084 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
1085 $pf = $pkg->fromPackageFile($packagexml, PEAR_VALIDATE_NORMAL);
1086 PEAR::staticPopErrorHandling();
1087 if (PEAR::isError($pf)) {
1088 if (is_array($pf->getUserInfo())) {
1089 foreach ($pf->getUserInfo() as $warning) {
1090 $this->ui->outputData($warning['message']);
1093 return $this->raiseError($pf);
1096 if (is_a($pf, 'PEAR_PackageFile_v2')) {
1097 $this->ui->outputData($packagexml . ' is already a package.xml version 2.0');
1101 $gen = &$pf->getDefaultGenerator();
1102 $newpf = &$gen->toV2();
1103 $newpf->setPackagefile($newpackagexml);
1104 $gen = &$newpf->getDefaultGenerator();
1105 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
1106 $state = (isset($options['flat']) ? PEAR_VALIDATE_PACKAGING : PEAR_VALIDATE_NORMAL);
1107 $saved = $gen->toPackageFile(dirname($newpackagexml), $state, basename($newpackagexml));
1108 PEAR::staticPopErrorHandling();
1109 if (PEAR::isError($saved)) {
1110 if (is_array($saved->getUserInfo())) {
1111 foreach ($saved->getUserInfo() as $warning) {
1112 $this->ui->outputData($warning['message']);
1116 $this->ui->outputData($saved->getMessage());
1120 $this->ui->outputData('Wrote new version 2.0 package.xml to "' . $saved . '"');