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;
|
||||
|
||||
/** 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 $transactions = array();
|
||||
var $file_operations = array();
|
||||
|
||||
// }}}
|
||||
|
||||
|
@ -104,7 +112,7 @@ class PEAR_Installer extends PEAR_Common
|
|||
*/
|
||||
function PEAR_Installer(&$ui)
|
||||
{
|
||||
$this->PEAR_Common();
|
||||
parent::PEAR_Common();
|
||||
$this->setFrontendObject($ui);
|
||||
$this->debug = $this->config->get('verbose');
|
||||
$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)
|
||||
{
|
||||
static $os;
|
||||
ini_set("track_errors", 1);
|
||||
if (isset($atts['platform'])) {
|
||||
if (empty($os)) {
|
||||
include_once "OS/Guess.php";
|
||||
|
@ -188,7 +197,6 @@ class PEAR_Installer extends PEAR_Common
|
|||
$this->source_files++;
|
||||
return;
|
||||
default:
|
||||
// Files with no role will end in "/"
|
||||
return $this->raiseError("Invalid role `$atts[role]' for file $file");
|
||||
}
|
||||
if (!empty($atts['baseinstalldir'])) {
|
||||
|
@ -210,8 +218,9 @@ class PEAR_Installer extends PEAR_Common
|
|||
DIRECTORY_SEPARATOR,
|
||||
array($dest_file, $orig_file));
|
||||
$installed_as = $dest_file;
|
||||
$dest_file = $this->_prependPath($dest_file, $this->installroot);
|
||||
$dest_dir = dirname($dest_file);
|
||||
$final_dest_file = $this->_prependPath($dest_file, $this->installroot);
|
||||
$dest_dir = dirname($final_dest_file);
|
||||
$dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
|
||||
if (!@is_dir($dest_dir)) {
|
||||
if (!$this->mkDirHier($dest_dir)) {
|
||||
return $this->raiseError("failed to mkdir $dest_dir",
|
||||
|
@ -255,23 +264,26 @@ class PEAR_Installer extends PEAR_Common
|
|||
$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)) {
|
||||
$contents = str_replace($subst_from, $subst_to, $contents);
|
||||
}
|
||||
$wp = @fopen($dest_file, "w");
|
||||
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);
|
||||
}
|
||||
fwrite($wp, $contents);
|
||||
fclose($wp);
|
||||
}
|
||||
if (isset($md5sum)) {
|
||||
if ($md5sum == $atts['md5sum']) {
|
||||
$this->log(3, "md5sum ok: $dest_file");
|
||||
$this->log(3, "md5sum ok: $final_dest_file");
|
||||
} 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) {
|
||||
|
@ -281,18 +293,128 @@ class PEAR_Installer extends PEAR_Common
|
|||
} else {
|
||||
$mode = 0666 & ~(int)octdec($this->config->get('umask'));
|
||||
}
|
||||
$this->addFileOperation("chmod", array($mode, $dest_file));
|
||||
if (!@chmod($dest_file, $mode)) {
|
||||
$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
|
||||
$this->pkginfo['filelist'][$file]['installed_as'] = $installed_as;
|
||||
|
||||
$this->log(2, "installed: $dest_file");
|
||||
//$this->log(2, "installed: $dest_file");
|
||||
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()
|
||||
|
||||
|
@ -310,6 +432,15 @@ class PEAR_Installer extends PEAR_Common
|
|||
return $package;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ mkDirHier($dir)
|
||||
|
||||
function mkDirHier($dir)
|
||||
{
|
||||
$this->addFileOperation('mkdir', $dir);
|
||||
return parent::mkDirHier($dir);
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
// {{{ _prependPath($path, $prepend)
|
||||
|
@ -550,6 +681,7 @@ class PEAR_Installer extends PEAR_Common
|
|||
$this->popExpect();
|
||||
if (PEAR::isError($res)) {
|
||||
if (empty($options['force'])) {
|
||||
$this->revertFileTransaction();
|
||||
return $this->raiseError($res);
|
||||
} else {
|
||||
$this->log(0, "Warning: " . $res->getMessage());
|
||||
|
@ -567,6 +699,7 @@ class PEAR_Installer extends PEAR_Common
|
|||
$bob->debug = $this->debug;
|
||||
$built = $bob->build($descfile, array(&$this, '_buildCallback'));
|
||||
if (PEAR::isError($built)) {
|
||||
$this->revertFileTransaction();
|
||||
return $built;
|
||||
}
|
||||
foreach ($built as $ext) {
|
||||
|
@ -576,6 +709,7 @@ class PEAR_Installer extends PEAR_Common
|
|||
$this->log(3, "+ cp $ext[file] ext_dir");
|
||||
$copyto = $this->_prependPath($dest, $this->installroot);
|
||||
if (!@copy($ext['file'], $copyto)) {
|
||||
$this->revertFileTransaction();
|
||||
return $this->raiseError("failed to copy $bn to $copyto");
|
||||
}
|
||||
$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 -----------------------
|
||||
if (empty($options['upgrade'])) {
|
||||
// if 'force' is used, replace the info in registry
|
||||
|
|
|
@ -31,50 +31,13 @@
|
|||
</maintainer>
|
||||
</maintainers>
|
||||
<release>
|
||||
<version>1.0b1</version>
|
||||
<version>1.0b2</version>
|
||||
<state>stable</state>
|
||||
<date>2002-10-12</date>
|
||||
<date>2002-11-11</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
|
||||
* installer aborts failed installs nicely (using
|
||||
file "transactions")
|
||||
</notes>
|
||||
<filelist>
|
||||
<file role="data" name="package.dtd"/>
|
||||
|
@ -125,6 +88,58 @@ Bugfixes, PEAR Library:
|
|||
</deps>
|
||||
</release>
|
||||
<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>
|
||||
<version>0.90</version>
|
||||
<state>beta</state>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue