mirror of
https://github.com/php/php-src.git
synced 2025-08-19 08:49:28 +02:00
* implemented file transactions so installs may be safely aborted
* preparing 1.0b2 release
This commit is contained in:
parent
609992baeb
commit
888a9bd2fe
2 changed files with 206 additions and 52 deletions
|
@ -87,9 +87,17 @@ class PEAR_Installer extends PEAR_Common
|
||||||
var $registry;
|
var $registry;
|
||||||
|
|
||||||
/** List of file transactions queued for an install/upgrade/uninstall.
|
/** List of file transactions queued for an install/upgrade/uninstall.
|
||||||
|
*
|
||||||
|
* Format:
|
||||||
|
* array(
|
||||||
|
* 0 => array("rename => array("from-file", "to-file")),
|
||||||
|
* 1 => array("delete" => array("file-to-delete")),
|
||||||
|
* ...
|
||||||
|
* )
|
||||||
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
var $transactions = array();
|
var $file_operations = array();
|
||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
|
@ -104,7 +112,7 @@ class PEAR_Installer extends PEAR_Common
|
||||||
*/
|
*/
|
||||||
function PEAR_Installer(&$ui)
|
function PEAR_Installer(&$ui)
|
||||||
{
|
{
|
||||||
$this->PEAR_Common();
|
parent::PEAR_Common();
|
||||||
$this->setFrontendObject($ui);
|
$this->setFrontendObject($ui);
|
||||||
$this->debug = $this->config->get('verbose');
|
$this->debug = $this->config->get('verbose');
|
||||||
$this->registry = &new PEAR_Registry($this->config->get('php_dir'));
|
$this->registry = &new PEAR_Registry($this->config->get('php_dir'));
|
||||||
|
@ -156,6 +164,7 @@ class PEAR_Installer extends PEAR_Common
|
||||||
function _installFile($file, $atts, $tmp_path)
|
function _installFile($file, $atts, $tmp_path)
|
||||||
{
|
{
|
||||||
static $os;
|
static $os;
|
||||||
|
ini_set("track_errors", 1);
|
||||||
if (isset($atts['platform'])) {
|
if (isset($atts['platform'])) {
|
||||||
if (empty($os)) {
|
if (empty($os)) {
|
||||||
include_once "OS/Guess.php";
|
include_once "OS/Guess.php";
|
||||||
|
@ -188,7 +197,6 @@ class PEAR_Installer extends PEAR_Common
|
||||||
$this->source_files++;
|
$this->source_files++;
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
// Files with no role will end in "/"
|
|
||||||
return $this->raiseError("Invalid role `$atts[role]' for file $file");
|
return $this->raiseError("Invalid role `$atts[role]' for file $file");
|
||||||
}
|
}
|
||||||
if (!empty($atts['baseinstalldir'])) {
|
if (!empty($atts['baseinstalldir'])) {
|
||||||
|
@ -210,8 +218,9 @@ class PEAR_Installer extends PEAR_Common
|
||||||
DIRECTORY_SEPARATOR,
|
DIRECTORY_SEPARATOR,
|
||||||
array($dest_file, $orig_file));
|
array($dest_file, $orig_file));
|
||||||
$installed_as = $dest_file;
|
$installed_as = $dest_file;
|
||||||
$dest_file = $this->_prependPath($dest_file, $this->installroot);
|
$final_dest_file = $this->_prependPath($dest_file, $this->installroot);
|
||||||
$dest_dir = dirname($dest_file);
|
$dest_dir = dirname($final_dest_file);
|
||||||
|
$dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
|
||||||
if (!@is_dir($dest_dir)) {
|
if (!@is_dir($dest_dir)) {
|
||||||
if (!$this->mkDirHier($dest_dir)) {
|
if (!$this->mkDirHier($dest_dir)) {
|
||||||
return $this->raiseError("failed to mkdir $dest_dir",
|
return $this->raiseError("failed to mkdir $dest_dir",
|
||||||
|
@ -255,23 +264,26 @@ class PEAR_Installer extends PEAR_Common
|
||||||
$subst_to[] = $to;
|
$subst_to[] = $to;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->log(3, "doing ".sizeof($subst_from)." substitution(s) for $dest_file");
|
$this->log(3, "doing ".sizeof($subst_from)." substitution(s) for $final_dest_file");
|
||||||
if (sizeof($subst_from)) {
|
if (sizeof($subst_from)) {
|
||||||
$contents = str_replace($subst_from, $subst_to, $contents);
|
$contents = str_replace($subst_from, $subst_to, $contents);
|
||||||
}
|
}
|
||||||
$wp = @fopen($dest_file, "w");
|
$wp = @fopen($dest_file, "w");
|
||||||
if (!is_resource($wp)) {
|
if (!is_resource($wp)) {
|
||||||
return $this->raiseError("failed to create $dest_file",
|
return $this->raiseError("failed to create $dest_file: $php_errormsg",
|
||||||
|
PEAR_INSTALLER_FAILED);
|
||||||
|
}
|
||||||
|
if (!fwrite($wp, $contents)) {
|
||||||
|
return $this->raiseError("failed writing to $dest_file: $php_errormsg",
|
||||||
PEAR_INSTALLER_FAILED);
|
PEAR_INSTALLER_FAILED);
|
||||||
}
|
}
|
||||||
fwrite($wp, $contents);
|
|
||||||
fclose($wp);
|
fclose($wp);
|
||||||
}
|
}
|
||||||
if (isset($md5sum)) {
|
if (isset($md5sum)) {
|
||||||
if ($md5sum == $atts['md5sum']) {
|
if ($md5sum == $atts['md5sum']) {
|
||||||
$this->log(3, "md5sum ok: $dest_file");
|
$this->log(3, "md5sum ok: $final_dest_file");
|
||||||
} else {
|
} else {
|
||||||
$this->log(0, "warning : bad md5sum for file $dest_file");
|
$this->log(0, "warning : bad md5sum for file $final_dest_file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!OS_WINDOWS) {
|
if (!OS_WINDOWS) {
|
||||||
|
@ -281,18 +293,128 @@ class PEAR_Installer extends PEAR_Common
|
||||||
} else {
|
} else {
|
||||||
$mode = 0666 & ~(int)octdec($this->config->get('umask'));
|
$mode = 0666 & ~(int)octdec($this->config->get('umask'));
|
||||||
}
|
}
|
||||||
|
$this->addFileOperation("chmod", array($mode, $dest_file));
|
||||||
if (!@chmod($dest_file, $mode)) {
|
if (!@chmod($dest_file, $mode)) {
|
||||||
$this->log(0, "failed to change mode of $dest_file");
|
$this->log(0, "failed to change mode of $dest_file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$this->addFileOperation("rename", array($dest_file, $final_dest_file));
|
||||||
|
|
||||||
|
// XXX SHOULD BE DONE ONLY AFTER COMMIT
|
||||||
// Store the full path where the file was installed for easy unistall
|
// Store the full path where the file was installed for easy unistall
|
||||||
$this->pkginfo['filelist'][$file]['installed_as'] = $installed_as;
|
$this->pkginfo['filelist'][$file]['installed_as'] = $installed_as;
|
||||||
|
|
||||||
$this->log(2, "installed: $dest_file");
|
//$this->log(2, "installed: $dest_file");
|
||||||
return PEAR_INSTALLER_OK;
|
return PEAR_INSTALLER_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
// {{{ addFileOperation()
|
||||||
|
|
||||||
|
function addFileOperation($type, $data)
|
||||||
|
{
|
||||||
|
$this->log(3, "adding to transaction: $type " . implode(" ", $data));
|
||||||
|
$this->file_operations[] = array($type, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
// {{{ startFileTransaction()
|
||||||
|
|
||||||
|
function startFileTransaction($revert_in_case = false)
|
||||||
|
{
|
||||||
|
if (count($this->file_operations) && $revert_in_case) {
|
||||||
|
$this->revertFileTransaction();
|
||||||
|
}
|
||||||
|
$this->file_operations = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
// {{{ commitFileTransaction()
|
||||||
|
|
||||||
|
function commitFileTransaction()
|
||||||
|
{
|
||||||
|
$n = count($this->file_operations);
|
||||||
|
$this->log(2, "about to commit $n file operations");
|
||||||
|
// first, check permissions and such manually
|
||||||
|
$errors = array();
|
||||||
|
foreach ($this->file_operations as $tr) {
|
||||||
|
list($type, $data) = $tr;
|
||||||
|
switch ($type) {
|
||||||
|
case 'rename':
|
||||||
|
// check that dest dir. is writable
|
||||||
|
if (!is_writable(dirname($data[1]))) {
|
||||||
|
$errors[] = "permission denied ($type): $data[1]";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'chmod':
|
||||||
|
// check that file is writable
|
||||||
|
if (!is_writable($data[1])) {
|
||||||
|
$errors[] = "permission denied ($type): $data[1]";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'delete':
|
||||||
|
// check that directory is writable
|
||||||
|
if (!is_writable(dirname($data[0]))) {
|
||||||
|
$errors[] = "permission denied ($type): $data[0]";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
$m = sizeof($errors);
|
||||||
|
if ($m > 0) {
|
||||||
|
foreach ($errors as $error) {
|
||||||
|
$this->log(1, $error);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// really commit the transaction
|
||||||
|
foreach ($this->file_operations as $tr) {
|
||||||
|
list($type, $data) = $tr;
|
||||||
|
switch ($type) {
|
||||||
|
case 'rename':
|
||||||
|
@rename($data[0], $data[1]);
|
||||||
|
break;
|
||||||
|
case 'chmod':
|
||||||
|
@chmod($data[0], $data[1]);
|
||||||
|
break;
|
||||||
|
case 'delete':
|
||||||
|
@unlink($data[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->log(2, "successfully commited $n file operations");
|
||||||
|
$this->file_operations = array();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
// {{{ revertFileTransaction()
|
||||||
|
|
||||||
|
function revertFileTransaction()
|
||||||
|
{
|
||||||
|
$n = count($this->file_operations);
|
||||||
|
$this->log(2, "reverting $n file operations");
|
||||||
|
foreach ($this->file_operations as $tr) {
|
||||||
|
list($type, $data) = $tr;
|
||||||
|
switch ($type) {
|
||||||
|
case 'rename':
|
||||||
|
@unlink($data[0]);
|
||||||
|
$this->log(3, "+ rm $data[0]");
|
||||||
|
break;
|
||||||
|
case 'mkdir':
|
||||||
|
@rmdir($data[0]);
|
||||||
|
$this->log(3, "+ rmdir $data[0]");
|
||||||
|
break;
|
||||||
|
case 'chmod':
|
||||||
|
break;
|
||||||
|
case 'delete':
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->file_operations = array();
|
||||||
|
}
|
||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
// {{{ getPackageDownloadUrl()
|
// {{{ getPackageDownloadUrl()
|
||||||
|
|
||||||
|
@ -310,6 +432,15 @@ class PEAR_Installer extends PEAR_Common
|
||||||
return $package;
|
return $package;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
// {{{ mkDirHier($dir)
|
||||||
|
|
||||||
|
function mkDirHier($dir)
|
||||||
|
{
|
||||||
|
$this->addFileOperation('mkdir', $dir);
|
||||||
|
return parent::mkDirHier($dir);
|
||||||
|
}
|
||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
// {{{ _prependPath($path, $prepend)
|
// {{{ _prependPath($path, $prepend)
|
||||||
|
@ -550,6 +681,7 @@ class PEAR_Installer extends PEAR_Common
|
||||||
$this->popExpect();
|
$this->popExpect();
|
||||||
if (PEAR::isError($res)) {
|
if (PEAR::isError($res)) {
|
||||||
if (empty($options['force'])) {
|
if (empty($options['force'])) {
|
||||||
|
$this->revertFileTransaction();
|
||||||
return $this->raiseError($res);
|
return $this->raiseError($res);
|
||||||
} else {
|
} else {
|
||||||
$this->log(0, "Warning: " . $res->getMessage());
|
$this->log(0, "Warning: " . $res->getMessage());
|
||||||
|
@ -567,6 +699,7 @@ class PEAR_Installer extends PEAR_Common
|
||||||
$bob->debug = $this->debug;
|
$bob->debug = $this->debug;
|
||||||
$built = $bob->build($descfile, array(&$this, '_buildCallback'));
|
$built = $bob->build($descfile, array(&$this, '_buildCallback'));
|
||||||
if (PEAR::isError($built)) {
|
if (PEAR::isError($built)) {
|
||||||
|
$this->revertFileTransaction();
|
||||||
return $built;
|
return $built;
|
||||||
}
|
}
|
||||||
foreach ($built as $ext) {
|
foreach ($built as $ext) {
|
||||||
|
@ -576,6 +709,7 @@ class PEAR_Installer extends PEAR_Common
|
||||||
$this->log(3, "+ cp $ext[file] ext_dir");
|
$this->log(3, "+ cp $ext[file] ext_dir");
|
||||||
$copyto = $this->_prependPath($dest, $this->installroot);
|
$copyto = $this->_prependPath($dest, $this->installroot);
|
||||||
if (!@copy($ext['file'], $copyto)) {
|
if (!@copy($ext['file'], $copyto)) {
|
||||||
|
$this->revertFileTransaction();
|
||||||
return $this->raiseError("failed to copy $bn to $copyto");
|
return $this->raiseError("failed to copy $bn to $copyto");
|
||||||
}
|
}
|
||||||
$pkginfo['filelist'][$bn] = array(
|
$pkginfo['filelist'][$bn] = array(
|
||||||
|
@ -589,6 +723,11 @@ class PEAR_Installer extends PEAR_Common
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$this->commitFileTransaction()) {
|
||||||
|
$this->revertFileTransaction();
|
||||||
|
return $this->raiseError("commit failed", PEAR_INSTALLER_FAILED);
|
||||||
|
}
|
||||||
|
|
||||||
// Register that the package is installed -----------------------
|
// Register that the package is installed -----------------------
|
||||||
if (empty($options['upgrade'])) {
|
if (empty($options['upgrade'])) {
|
||||||
// if 'force' is used, replace the info in registry
|
// if 'force' is used, replace the info in registry
|
||||||
|
|
|
@ -31,50 +31,13 @@
|
||||||
</maintainer>
|
</maintainer>
|
||||||
</maintainers>
|
</maintainers>
|
||||||
<release>
|
<release>
|
||||||
<version>1.0b1</version>
|
<version>1.0b2</version>
|
||||||
<state>stable</state>
|
<state>stable</state>
|
||||||
<date>2002-10-12</date>
|
<date>2002-11-11</date>
|
||||||
<notes>
|
<notes>
|
||||||
New Features, Installer:
|
New Features, Installer:
|
||||||
* new command: "pear makerpm"
|
* installer aborts failed installs nicely (using
|
||||||
* new command: "pear search"
|
file "transactions")
|
||||||
* new command: "pear upgrade-all"
|
|
||||||
* new command: "pear config-help"
|
|
||||||
* new command: "pear sign"
|
|
||||||
* Windows support for "pear build" (requires
|
|
||||||
msdev)
|
|
||||||
* new dependency type: "zend"
|
|
||||||
* XML-RPC results may now be cached (see
|
|
||||||
cache_dir and cache_ttl config)
|
|
||||||
* HTTP proxy authorization support
|
|
||||||
* install/upgrade install-root support
|
|
||||||
|
|
||||||
Bugfixes, Installer:
|
|
||||||
* fix for XML-RPC bug that made some remote
|
|
||||||
commands fail
|
|
||||||
* fix problems under Windows with
|
|
||||||
DIRECTORY_SEPARATOR
|
|
||||||
* lots of other minor fixes
|
|
||||||
* --force option did not work for "pear install
|
|
||||||
Package"
|
|
||||||
* http downloader used "4.2.1" rather than
|
|
||||||
"PHP/4.2.1" as user agent
|
|
||||||
* bending over a little more to figure out how
|
|
||||||
PHP is installed
|
|
||||||
* "platform" file attribute was not included
|
|
||||||
during "pear package"
|
|
||||||
|
|
||||||
New Features, PEAR Library:
|
|
||||||
* added PEAR::loadExtension($ext)
|
|
||||||
* added PEAR::delExpect()
|
|
||||||
* System::mkTemp() now cleans up at shutdown
|
|
||||||
* defined PEAR_ZE2 constant (boolean)
|
|
||||||
* added PEAR::throwError() with a simpler API
|
|
||||||
than raiseError()
|
|
||||||
|
|
||||||
Bugfixes, PEAR Library:
|
|
||||||
* ZE2 compatibility fixes
|
|
||||||
* use getenv() as fallback for $_ENV
|
|
||||||
</notes>
|
</notes>
|
||||||
<filelist>
|
<filelist>
|
||||||
<file role="data" name="package.dtd"/>
|
<file role="data" name="package.dtd"/>
|
||||||
|
@ -125,6 +88,58 @@ Bugfixes, PEAR Library:
|
||||||
</deps>
|
</deps>
|
||||||
</release>
|
</release>
|
||||||
<changelog>
|
<changelog>
|
||||||
|
<release>
|
||||||
|
<version>1.0b1</version>
|
||||||
|
<state>stable</state>
|
||||||
|
<date>2002-10-12</date>
|
||||||
|
<notes>
|
||||||
|
New Features, Installer:
|
||||||
|
* new command: "pear makerpm"
|
||||||
|
* new command: "pear search"
|
||||||
|
* new command: "pear upgrade-all"
|
||||||
|
* new command: "pear config-help"
|
||||||
|
* new command: "pear sign"
|
||||||
|
* Windows support for "pear build" (requires
|
||||||
|
msdev)
|
||||||
|
* new dependency type: "zend"
|
||||||
|
* XML-RPC results may now be cached (see
|
||||||
|
cache_dir and cache_ttl config)
|
||||||
|
* HTTP proxy authorization support
|
||||||
|
* install/upgrade install-root support
|
||||||
|
|
||||||
|
Bugfixes, Installer:
|
||||||
|
* fix for XML-RPC bug that made some remote
|
||||||
|
commands fail
|
||||||
|
* fix problems under Windows with
|
||||||
|
DIRECTORY_SEPARATOR
|
||||||
|
* lots of other minor fixes
|
||||||
|
* --force option did not work for "pear install
|
||||||
|
Package"
|
||||||
|
* http downloader used "4.2.1" rather than
|
||||||
|
"PHP/4.2.1" as user agent
|
||||||
|
* bending over a little more to figure out how
|
||||||
|
PHP is installed
|
||||||
|
* "platform" file attribute was not included
|
||||||
|
during "pear package"
|
||||||
|
|
||||||
|
New Features, PEAR Library:
|
||||||
|
* added PEAR::loadExtension($ext)
|
||||||
|
* added PEAR::delExpect()
|
||||||
|
* System::mkTemp() now cleans up at shutdown
|
||||||
|
* defined PEAR_ZE2 constant (boolean)
|
||||||
|
* added PEAR::throwError() with a simpler API
|
||||||
|
than raiseError()
|
||||||
|
|
||||||
|
Bugfixes, PEAR Library:
|
||||||
|
* ZE2 compatibility fixes
|
||||||
|
* use getenv() as fallback for $_ENV
|
||||||
|
</notes>
|
||||||
|
<deps>
|
||||||
|
<dep type="php" rel="ge" version="4.1"/>
|
||||||
|
<dep type="pkg" rel="ge" version="0.4">Archive_Tar</dep>
|
||||||
|
<dep type="pkg" rel="ge" version="0.11">Console_Getopt</dep>
|
||||||
|
</deps>
|
||||||
|
</release>
|
||||||
<release>
|
<release>
|
||||||
<version>0.90</version>
|
<version>0.90</version>
|
||||||
<state>beta</state>
|
<state>beta</state>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue