Source for file Package.php
Documentation is available at Package.php
* PEAR_Command_Package (package, package-validate, cvsdiff, cvstag, package-dependencies,
* sign, makerpm, convert commands)
* @author Stig Bakken <ssb@php.net>
* @author Martin Jansen <mj@php.net>
* @author Greg Beaver <cellog@php.net>
* @copyright 1997-2009 The Authors
* @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version CVS: $Id: Package.php 313024 2011-07-06 19:51:24Z dufuz $
* @link http://pear.php.net/package/PEAR
* @since File available since Release 0.1
require_once 'PEAR/Command/Common.php';
* PEAR commands for login/logout
* @author Stig Bakken <ssb@php.net>
* @author Martin Jansen <mj@php.net>
* @author Greg Beaver <cellog@php.net>
* @copyright 1997-2009 The Authors
* @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version Release: @package_version@
* @link http://pear.php.net/package/PEAR
* @since Class available since Release 0.1
'summary' => 'Build Package',
'function' => 'doPackage',
'doc' => 'Do not gzip the package file'
'doc' => 'Print the name of the packaged file.',
'doc' => '[descfile] [descfile2]
Creates a PEAR package from its description file (usually called
package.xml). If a second packagefile is passed in, then
the packager will check to make sure that one is a package.xml
version 1.0, and the other is a package.xml version 2.0. The
package.xml version 1.0 will be saved as "package.xml" in the archive,
and the other as "package2.xml" in the archive"
'package-validate' => array (
'summary' => 'Validate Package Consistency',
'function' => 'doPackageValidate',
'summary' => 'Run a "cvs diff" for all files in a package',
'function' => 'doCvsDiff',
'doc' => 'Be really quiet',
'doc' => 'Diff against revision of DATE',
'doc' => 'Diff against tag for package release REL',
'doc' => 'Diff against revision REV',
'doc' => 'Generate context diff',
'doc' => 'Generate unified diff',
'doc' => 'Ignore case, consider upper- and lower-case letters equivalent',
'ignore-whitespace' => array (
'doc' => 'Ignore changes in amount of white space',
'ignore-blank-lines' => array (
'doc' => 'Ignore changes that insert or delete blank lines',
'doc' => 'Report only whether the files differ, no details',
'doc' => 'Don\'t do anything, just pretend',
Compares all the files in a package. Without any options, this
command will compare the current code with the last checked-in code.
Using the -r or -R option you may compare the current code with that
'summary' => 'Set SVN Release Tag',
'function' => 'doSvnTag',
'doc' => 'Move (slide) tag if it exists',
'doc' => 'Don\'t do anything, just pretend',
'doc' => '<package.xml> [files...]
Sets a SVN tag on all files in a package. Use this command after you have
packaged a distribution tarball with the "package" command to tag what
revisions of what files were in that release. If need to fix something
after running svntag once, but before the tarball is released to the public,
use the "slide" option to move the release tag.
to include files (such as a second package.xml, or tests not included in the
release), pass them as additional parameters.
'summary' => 'Set CVS Release Tag',
'function' => 'doCvsTag',
'doc' => 'Be really quiet',
'doc' => 'Move (slide) tag if it exists',
'doc' => 'Don\'t do anything, just pretend',
'doc' => '<package.xml> [files...]
Sets a CVS tag on all files in a package. Use this command after you have
packaged a distribution tarball with the "package" command to tag what
revisions of what files were in that release. If need to fix something
after running cvstag once, but before the tarball is released to the public,
use the "slide" option to move the release tag.
to include files (such as a second package.xml, or tests not included in the
release), pass them as additional parameters.
'package-dependencies' => array (
'summary' => 'Show package dependencies',
'function' => 'doPackageDependencies',
'doc' => '<package-file> or <package.xml> or <install-package-name>
List all dependencies the package has.
Can take a tgz / tar file, package.xml or a package name of an installed package.'
'summary' => 'Sign a package distribution file',
'doc' => 'Display GnuPG output',
Signs a package distribution (.tar or .tgz) file with GnuPG.',
'summary' => 'Builds an RPM spec file from a PEAR package',
'function' => 'doMakeRPM',
'spec-template' => array (
'doc' => 'Use FILE as RPM spec file template'
'doc' => 'Use FORMAT as format string for RPM package name, %s is replaced
by the PEAR package name, defaults to "PEAR::%s".',
Creates an RPM .spec file for wrapping a PEAR package inside an RPM
package. Intended to be used from the SPECS directory, with the PEAR
package tarball in the SOURCES directory:
$ pear makerpm ../SOURCES/Net_Socket-1.0.tgz
Wrote RPM spec file PEAR::Net_Geo-1.0.spec
$ rpm -bb PEAR::Net_Socket-1.0.spec
Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
'summary' => 'Convert a package.xml 1.0 to package.xml 2.0 format',
'function' => 'doConvert',
'doc' => 'do not beautify the filelist.',
'doc' => '[descfile] [descfile2]
Converts a package.xml in 1.0 format into a package.xml
in 2.0 format. The new file will be named package2.xml by default,
and package.xml will be used as the old file by default.
This is not the most intelligent conversion, and should only be
used for automated conversion or learning the format.
* PEAR_Command_Package constructor.
function _displayValidationResults ($err, $warn, $strict = false )
$this->output .= " Error: $e\n";
$this->output .= " Warning: $w\n";
$this->output .= sprintf('Validation: %d error(s), %d warning(s)'. "\n",
if ($strict && count($err) > 0 ) {
$this->output .= "Fix these errors and try again.";
require_once 'PEAR/Packager.php';
require_once 'PEAR/Common.php';
require_once 'PEAR/PackageFile.php';
function doPackage($command, $options, $params)
$pkginfofile = isset ($params[0 ]) ? $params[0 ] : 'package.xml';
$pkg2 = isset ($params[1 ]) ? $params[1 ] : null;
if (!$pkg2 && !isset ($params[0 ]) && file_exists('package2.xml')) {
$compress = empty ($options['nocompress']) ? true : false;
$result = $packager->package ($pkginfofile, $compress, $pkg2);
// Don't want output, only the package file name just created
if (isset ($options['showname'])) {
$this->ui->outputData ($this->output, $command);
if (count($params) < 1 ) {
$params[0 ] = 'package.xml';
$archive = $info->getArchiveFile ();
$tar = &new Archive_Tar ($archive);
$tar->extract (dirname($info->getPackageFile ()));
$info->setPackageFile (dirname($info->getPackageFile ()) . DIRECTORY_SEPARATOR .
$info->getPackage () . '-' . $info->getVersion () . DIRECTORY_SEPARATOR .
if ($info->getPackagexmlVersion () == '2.0') {
$info->flattenFileList ();
if ($errors = $info->getValidationWarnings ()) {
foreach ($errors as $error) {
if ($error['level'] == 'warning') {
$warn[] = $error['message'];
$err[] = $error['message'];
$this->_displayValidationResults ($err, $warn);
$this->ui->outputData ($this->output, $command);
function doSvnTag($command, $options, $params)
if (count($params) < 1 ) {
return $this->raiseError(" $command: missing parameter: $help[0]" );
if (!$info->validate ()) {
foreach ($info->getValidationWarnings () as $error) {
if ($error['level'] == 'warning') {
$warn[] = $error['message'];
$err[] = $error['message'];
if (!$this->_displayValidationResults ($err, $warn, true )) {
$this->ui->outputData ($this->output, $command);
$version = $info->getVersion ();
$package = $info->getName ();
$svntag = " $package-$version";
if (isset ($options['delete'])) {
return $this->_svnRemoveTag ($version, $package, $svntag, $packageFile, $options);
$path = $this->_svnFindPath ($packageFile);
// Check if there are any modified files
while ($line = fgets($fp, 1024 )) {
$out .= rtrim($line). "\n";
if (!isset ($options['quiet']) && strpos($out, 'item="modified"')) {
'prompt' => 'You have files in your SVN checkout (' . $path['from'] . ') that have been modified but not commited, do you still want to tag ' . $version . '?',
$answers = $this->ui->confirmDialog ($params);
if (!in_array($answers['modified'], array ('y', 'yes', 'on', '1'))) {
if (isset ($options['slide'])) {
$this->_svnRemoveTag ($version, $package, $svntag, $packageFile, $options);
// Check if tag already exists
$releaseTag = $path['local']['base'] . 'tags' . DIRECTORY_SEPARATOR . $svntag;
$existsCommand = 'svn ls ' . $path['base'] . 'tags/';
$fp = popen($existsCommand, "r");
while ($line = fgets($fp, 1024 )) {
$out .= rtrim($line). "\n";
$this->ui->outputData ($this->output, $command);
return $this->raiseError('SVN tag ' . $svntag . ' for ' . $package . ' already exists.');
} elseif (file_exists($path['local']['base'] . 'tags') === false ) {
return $this->raiseError('Can not locate the tags directory at ' . $path['local']['base'] . 'tags');
} elseif (is_writeable($path['local']['base'] . 'tags') === false ) {
return $this->raiseError('Can not write to the tag directory at ' . $path['local']['base'] . 'tags');
$makeCommand = 'svn mkdir ' . $releaseTag;
$this->output .= " + $makeCommand\n";
if (empty ($options['dry-run'])) {
// We need to create the tag dir.
$fp = popen($makeCommand, "r");
while ($line = fgets($fp, 1024 )) {
$out .= rtrim($line). "\n";
if (isset ($options['quiet'])) {
$command .= ' copy --parents ';
// add in additional files to be tagged (package files and such)
foreach ($files as $file) {
$file = $dir . DIRECTORY_SEPARATOR . $file;
if (empty ($options['dry-run'])) {
foreach ($commands as $command) {
$fp = popen($command, "r");
while ($line = fgets($fp, 1024 )) {
$command = 'svn ci -m "Tagging the ' . $version . ' release" ' . $releaseTag . "\n";
$this->output .= " + $command\n";
if (empty ($options['dry-run'])) {
$fp = popen($command, "r");
while ($line = fgets($fp, 1024 )) {
$this->ui->outputData ($this->output, $_cmd);
function _svnFindPath ($file)
$command = " svn info --xml $file";
$fp = popen($command, "r");
while ($line = fgets($fp, 1024 )) {
$xml .= rtrim($line). "\n";
$url_tag = strpos($xml, '<url>');
$url = substr($xml, $url_tag + 5 , strpos($xml, '</url>', $url_tag + 5 ) - ($url_tag + 5 ));
$path['base'] = substr($path['from'], 0 , strrpos($path['from'], '/') + 1 );
// Figure out the local paths - see http://pear.php.net/bugs/17463
$pos = strpos($file, DIRECTORY_SEPARATOR . 'trunk' . DIRECTORY_SEPARATOR );
$pos = strpos($file, DIRECTORY_SEPARATOR . 'branches' . DIRECTORY_SEPARATOR );
$path['local']['base'] = substr($file, 0 , $pos + 1 );
function _svnRemoveTag ($version, $package, $tag, $packageFile, $options)
if (isset ($options['quiet'])) {
$command .= ' -m "Removing tag for the ' . $version . ' release."';
$path = $this->_svnFindPath ($packageFile);
$command .= ' ' . $path['base'] . 'tags/' . $tag;
if ($this->config->get ('verbose') > 1 ) {
$this->output .= " + $command\n";
$this->output .= " + $command\n";
if (empty ($options['dry-run'])) {
$fp = popen($command, "r");
while ($line = fgets($fp, 1024 )) {
$this->ui->outputData ($this->output, $command);
function doCvsTag($command, $options, $params)
if (count($params) < 1 ) {
return $this->raiseError(" $command: missing parameter: $help[0]" );
if (!$info->validate ()) {
foreach ($info->getValidationWarnings () as $error) {
if ($error['level'] == 'warning') {
$warn[] = $error['message'];
$err[] = $error['message'];
if (!$this->_displayValidationResults ($err, $warn, true )) {
$this->ui->outputData ($this->output, $command);
$version = $info->getVersion ();
$cvstag = " RELEASE_$cvsversion";
if (isset ($options['quiet'])) {
if (isset ($options['reallyquiet'])) {
if (isset ($options['slide'])) {
if (isset ($options['delete'])) {
// add in additional files to be tagged
foreach ($files as $file) {
$file = $dir . DIRECTORY_SEPARATOR . $file;
if ($this->config->get ('verbose') > 1 ) {
$this->output .= " + $command\n";
$this->output .= " + $command\n";
if (empty ($options['dry-run'])) {
$fp = popen($command, "r");
while ($line = fgets($fp, 1024 )) {
$this->ui->outputData ($this->output, $_cmd);
function doCvsDiff($command, $options, $params)
return $this->raiseError(" $command: missing parameter: $help[0]" );
if (!$info->validate ()) {
foreach ($info->getValidationWarnings () as $error) {
if ($error['level'] == 'warning') {
$warn[] = $error['message'];
$err[] = $error['message'];
if (!$this->_displayValidationResults ($err, $warn, true )) {
$this->ui->outputData ($this->output, $command);
$info1 = $info->getFilelist ();
if (isset ($options['quiet'])) {
unset ($options['quiet']);
if (isset ($options['reallyquiet'])) {
unset ($options['reallyquiet']);
if (isset ($options['release'])) {
$cvsversion = preg_replace('/[^a-z0-9]/i', '_', $options['release']);
$cvstag = " RELEASE_$cvsversion";
$options['revision'] = $cvstag;
unset ($options['release']);
if (isset ($options['dry-run'])) {
unset ($options['dry-run']);
// the rest of the options are passed right on to "cvs diff"
foreach ($options as $option => $optarg) {
if (isset ($this->commands[$command]['options'][$option])) {
$arg = $this->commands[$command]['options'][$option]['arg'];
$short = $this->commands[$command]['options'][$option]['shortopt'];
$cmd .= $short ? " -$short" : " --$option";
foreach ($files as $file) {
if ($this->config->get ('verbose') > 1 ) {
while ($line = fgets($fp, 1024 )) {
$this->ui->outputData ($this->output, $command);
// $params[0] -> the PEAR package to list its information
if (count($params) !== 1 ) {
return $this->raiseError(" bad parameter(s), try \"help $command\"" );
$reg = $this->config->getRegistry ();
$info = $obj->fromArray ($reg->packageInfo ($params[0 ]));
$deps = $info->getDeps ();
if ($info->getPackagexmlVersion () == '1.0') {
'caption' => 'Dependencies for pear/' . $info->getPackage (),
'headline' => array ("Required?", "Type", "Name", "Relation", "Version"),
if (isset ($d['optional'])) {
if ($d['optional'] == 'yes') {
if (isset ($this->_deps_rel_trans[$d['rel']])) {
$rel = $this->_deps_rel_trans[$d['rel']];
if (isset ($this->_deps_type_trans[$d['type']])) {
$type = ucfirst($this->_deps_type_trans[$d['type']]);
if (isset ($d['version'])) {
$version = $d['version'];
$data['data'][] = array ($req, $type, $name, $rel, $version);
} else { // package.xml 2.0 dependencies display
require_once 'PEAR/Dependency2.php';
$deps = $info->getDependencies ();
$reg = &$this->config->getRegistry ();
'caption' => 'Dependencies for ' . $info->getPackage (),
'headline' => array ("Required?", "Type", "Name", 'Versioning', 'Group'),
foreach ($deps as $type => $subd) {
$req = ($type == 'required') ? 'Yes' : 'No';
$group = $subd['attribs']['name'];
foreach ($subd as $groupa) {
foreach ($groupa as $deptype => $depinfo) {
if ($deptype == 'attribs') {
if ($deptype == 'pearinstaller') {
$deptype = 'pear Installer';
if (!isset ($depinfo[0 ])) {
$depinfo = array ($depinfo);
foreach ($depinfo as $inf) {
if (isset ($inf['channel'])) {
$alias = $reg->channelAlias ($inf['channel']);
$alias = '(channel?) ' . $inf['channel'];
if (isset ($inf['name'])) {
} elseif (isset ($inf['pattern'])) {
$name .= $inf['pattern'];
if (isset ($inf['uri'])) {
$name .= ' [' . $inf['uri'] . ']';
if (isset ($inf['conflicts'])) {
$ver = $d->_getExtraString ($inf);
$data['data'][] = array ($req, ucfirst($deptype), $name,
$this->ui->outputData ($data, $command);
$this->ui->outputData ("This package does not have any dependencies.", $command);
function doSign($command, $options, $params)
// should move most of this code into PEAR_Packager
// so it'll be easy to implement "pear package --sign"
if (count($params) !== 1 ) {
return $this->raiseError(" bad parameter(s), try \"help $command\"" );
require_once 'System.php';
require_once 'Archive/Tar.php';
return $this->raiseError(" file does not exist: $params[0]" );
$tar = new Archive_Tar ($params[0 ]);
$tmpdir = $this->config->get ('temp_dir');
$tmpdir = System::mktemp(' -t "' . $tmpdir . '" -d pearsign');
if (!$tar->extractList ('package2.xml package.xml package.sig', $tmpdir)) {
return $this->raiseError("failed to extract tar file");
return $this->raiseError("package already signed");
$packagexml = 'package.xml';
$packagexml = 'package2.xml';
unlink(" $tmpdir/package.sig" );
return $this->raiseError(" Extracted file $tmpdir/$packagexml not found." );
$input = $this->ui->userDialog ($command,
array ('GnuPG Passphrase'),
$devnull = (isset ($options['verbose'])) ? '' : ' 2>/dev/null';
$gpg = popen(" gpg --batch --passphrase-fd 0 --armor --detach-sign --output $tmpdir/package.sig $tmpdir/$packagexml" . $devnull, "w");
if (!$tar->addModify (" $tmpdir/package.sig" , '', $tmpdir)) {
return $this->raiseError('failed adding signature to file');
$this->ui->outputData ("Package signed.", $command);
* For unit testing purposes
require_once 'PEAR/Installer.php';
* For unit testing purposes
if ($fp = @fopen('PEAR/Command/Packaging.php', 'r', true )) {
include_once 'PEAR/Command/Packaging.php';
$a = &new PEAR_Command_Packaging ($ui, $config);
function doMakeRPM($command, $options, $params)
// Check to see if PEAR_Command_Packaging is installed, and
// transparently switch to use the "make-rpm-spec" command from it
// instead, if it does. Otherwise, continue to use the old version
// of "makerpm" supplied with this package (PEAR).
if ($packaging_cmd !== null ) {
$this->ui->outputData ('PEAR_Command_Packaging is installed; using '.
'newer "make-rpm-spec" command instead');
return $packaging_cmd->run ('make-rpm-spec', $options, $params);
$this->ui->outputData ('WARNING: "pear makerpm" is no longer available; an '.
'improved version is available via "pear make-rpm-spec", which '.
'is available by installing PEAR_Command_Packaging');
function doConvert($command, $options, $params)
$packagexml = isset ($params[0 ]) ? $params[0 ] : 'package.xml';
$newpackagexml = isset ($params[1 ]) ? $params[1 ] : dirname($packagexml) .
DIRECTORY_SEPARATOR . 'package2.xml';
foreach ($pf->getUserInfo () as $warning) {
$this->ui->outputData ($warning['message']);
if (is_a($pf, 'PEAR_PackageFile_v2')) {
$this->ui->outputData ($packagexml . ' is already a package.xml version 2.0');
$gen = &$pf->getDefaultGenerator ();
$newpf->setPackagefile ($newpackagexml);
$gen = &$newpf->getDefaultGenerator ();
$saved = $gen->toPackageFile (dirname($newpackagexml), $state, basename($newpackagexml));
foreach ($saved->getUserInfo () as $warning) {
$this->ui->outputData ($warning['message']);
$this->ui->outputData ($saved->getMessage ());
$this->ui->outputData ('Wrote new version 2.0 package.xml to "' . $saved . '"');
Documentation generated on Wed, 06 Jul 2011 23:30:58 +0000 by phpDocumentor 1.4.3. PEAR Logo Copyright © PHP Group 2004.
|