Редакция 69 | Только различия | Учитывать пробелы | Содержимое файла | Авторство | Последнее изменение | Открыть журнал | RSS
Редакция 69 | Редакция 87 | ||
---|---|---|---|
1 | <?php
|
1 | <?php
|
2 | /**
|
2 | /**
|
3 | * PEAR_Installer
|
3 | * PEAR_Installer
|
4 | *
|
4 | *
|
5 | * PHP versions 4 and 5
|
5 | * PHP versions 4 and 5
|
6 | *
|
6 | *
|
7 | * LICENSE: This source file is subject to version 3.0 of the PHP license
|
7 | * LICENSE: This source file is subject to version 3.0 of the PHP license
|
8 | * that is available through the world-wide-web at the following URI:
|
8 | * that is available through the world-wide-web at the following URI:
|
9 | * http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
9 | * http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
10 | * the PHP License and are unable to obtain it through the web, please
|
10 | * the PHP License and are unable to obtain it through the web, please
|
11 | * send a note to license@php.net so we can mail you a copy immediately.
|
11 | * send a note to license@php.net so we can mail you a copy immediately.
|
12 | *
|
12 | *
|
13 | * @category pear
|
13 | * @category pear
|
14 | * @package PEAR
|
14 | * @package PEAR
|
15 | * @author Stig Bakken <ssb@php.net>
|
15 | * @author Stig Bakken <ssb@php.net>
|
16 | * @author Tomas V.V. Cox <cox@idecnet.com>
|
16 | * @author Tomas V.V. Cox <cox@idecnet.com>
|
17 | * @author Martin Jansen <mj@php.net>
|
17 | * @author Martin Jansen <mj@php.net>
|
18 | * @author Greg Beaver <cellog@php.net>
|
18 | * @author Greg Beaver <cellog@php.net>
|
19 | * @copyright 1997-2008 The PHP Group
|
19 | * @copyright 1997-2008 The PHP Group
|
20 | * @license http://www.php.net/license/3_0.txt PHP License 3.0
|
20 | * @license http://www.php.net/license/3_0.txt PHP License 3.0
|
21 | * @version CVS: $Id: Installer.php,v 1.253 2008/05/13 22:46:07 cellog Exp $
|
21 | * @version CVS: $Id: Installer.php,v 1.253 2008/05/13 22:46:07 cellog Exp $
|
22 | * @link http://pear.php.net/package/PEAR
|
22 | * @link http://pear.php.net/package/PEAR
|
23 | * @since File available since Release 0.1
|
23 | * @since File available since Release 0.1
|
24 | */
|
24 | */
|
25 | 25 | ||
26 | /**
|
26 | /**
|
27 | * Used for installation groups in package.xml 2.0 and platform exceptions
|
27 | * Used for installation groups in package.xml 2.0 and platform exceptions
|
28 | */
|
28 | */
|
29 | require_once 'OS/Guess.php'; |
29 | require_once 'OS/Guess.php'; |
30 | require_once 'PEAR/Downloader.php'; |
30 | require_once 'PEAR/Downloader.php'; |
31 | 31 | ||
32 | define('PEAR_INSTALLER_NOBINARY', -240); |
32 | define('PEAR_INSTALLER_NOBINARY', -240); |
33 | /**
|
33 | /**
|
34 | * Administration class used to install PEAR packages and maintain the
|
34 | * Administration class used to install PEAR packages and maintain the
|
35 | * installed package database.
|
35 | * installed package database.
|
36 | *
|
36 | *
|
37 | * @category pear
|
37 | * @category pear
|
38 | * @package PEAR
|
38 | * @package PEAR
|
39 | * @author Stig Bakken <ssb@php.net>
|
39 | * @author Stig Bakken <ssb@php.net>
|
40 | * @author Tomas V.V. Cox <cox@idecnet.com>
|
40 | * @author Tomas V.V. Cox <cox@idecnet.com>
|
41 | * @author Martin Jansen <mj@php.net>
|
41 | * @author Martin Jansen <mj@php.net>
|
42 | * @author Greg Beaver <cellog@php.net>
|
42 | * @author Greg Beaver <cellog@php.net>
|
43 | * @copyright 1997-2008 The PHP Group
|
43 | * @copyright 1997-2008 The PHP Group
|
44 | * @license http://www.php.net/license/3_0.txt PHP License 3.0
|
44 | * @license http://www.php.net/license/3_0.txt PHP License 3.0
|
45 | * @version Release: 1.7.2
|
45 | * @version Release: 1.7.2
|
46 | * @link http://pear.php.net/package/PEAR
|
46 | * @link http://pear.php.net/package/PEAR
|
47 | * @since Class available since Release 0.1
|
47 | * @since Class available since Release 0.1
|
48 | */
|
48 | */
|
49 | class PEAR_Installer extends PEAR_Downloader |
49 | class PEAR_Installer extends PEAR_Downloader |
50 | {
|
50 | {
|
51 | // {{{ properties
|
51 | // {{{ properties
|
52 | 52 | ||
53 | /** name of the package directory, for example Foo-1.0
|
53 | /** name of the package directory, for example Foo-1.0
|
54 | * @var string
|
54 | * @var string
|
55 | */
|
55 | */
|
56 | var $pkgdir; |
56 | var $pkgdir; |
57 | 57 | ||
58 | /** directory where PHP code files go
|
58 | /** directory where PHP code files go
|
59 | * @var string
|
59 | * @var string
|
60 | */
|
60 | */
|
61 | var $phpdir; |
61 | var $phpdir; |
62 | 62 | ||
63 | /** directory where PHP extension files go
|
63 | /** directory where PHP extension files go
|
64 | * @var string
|
64 | * @var string
|
65 | */
|
65 | */
|
66 | var $extdir; |
66 | var $extdir; |
67 | 67 | ||
68 | /** directory where documentation goes
|
68 | /** directory where documentation goes
|
69 | * @var string
|
69 | * @var string
|
70 | */
|
70 | */
|
71 | var $docdir; |
71 | var $docdir; |
72 | 72 | ||
73 | /** installation root directory (ala PHP's INSTALL_ROOT or
|
73 | /** installation root directory (ala PHP's INSTALL_ROOT or
|
74 | * automake's DESTDIR
|
74 | * automake's DESTDIR
|
75 | * @var string
|
75 | * @var string
|
76 | */
|
76 | */
|
77 | var $installroot = ''; |
77 | var $installroot = ''; |
78 | 78 | ||
79 | /** debug level
|
79 | /** debug level
|
80 | * @var int
|
80 | * @var int
|
81 | */
|
81 | */
|
82 | var $debug = 1; |
82 | var $debug = 1; |
83 | 83 | ||
84 | /** temporary directory
|
84 | /** temporary directory
|
85 | * @var string
|
85 | * @var string
|
86 | */
|
86 | */
|
87 | var $tmpdir; |
87 | var $tmpdir; |
88 | 88 | ||
89 | /**
|
89 | /**
|
90 | * PEAR_Registry object used by the installer
|
90 | * PEAR_Registry object used by the installer
|
91 | * @var PEAR_Registry
|
91 | * @var PEAR_Registry
|
92 | */
|
92 | */
|
93 | var $registry; |
93 | var $registry; |
94 | 94 | ||
95 | /**
|
95 | /**
|
96 | * array of PEAR_Downloader_Packages
|
96 | * array of PEAR_Downloader_Packages
|
97 | * @var array
|
97 | * @var array
|
98 | */
|
98 | */
|
99 | var $_downloadedPackages; |
99 | var $_downloadedPackages; |
100 | 100 | ||
101 | /** List of file transactions queued for an install/upgrade/uninstall.
|
101 | /** List of file transactions queued for an install/upgrade/uninstall.
|
102 | *
|
102 | *
|
103 | * Format:
|
103 | * Format:
|
104 | * array(
|
104 | * array(
|
105 | * 0 => array("rename => array("from-file", "to-file")),
|
105 | * 0 => array("rename => array("from-file", "to-file")),
|
106 | * 1 => array("delete" => array("file-to-delete")),
|
106 | * 1 => array("delete" => array("file-to-delete")),
|
107 | * ...
|
107 | * ...
|
108 | * )
|
108 | * )
|
109 | *
|
109 | *
|
110 | * @var array
|
110 | * @var array
|
111 | */
|
111 | */
|
112 | var $file_operations = array(); |
112 | var $file_operations = array(); |
113 | 113 | ||
114 | // }}}
|
114 | // }}}
|
115 | 115 | ||
116 | // {{{ constructor
|
116 | // {{{ constructor
|
117 | 117 | ||
118 | /**
|
118 | /**
|
119 | * PEAR_Installer constructor.
|
119 | * PEAR_Installer constructor.
|
120 | *
|
120 | *
|
121 | * @param object $ui user interface object (instance of PEAR_Frontend_*)
|
121 | * @param object $ui user interface object (instance of PEAR_Frontend_*)
|
122 | *
|
122 | *
|
123 | * @access public
|
123 | * @access public
|
124 | */
|
124 | */
|
125 | function PEAR_Installer(&$ui) |
125 | function PEAR_Installer(&$ui) |
126 | {
|
126 | {
|
127 | parent::PEAR_Common(); |
127 | parent::PEAR_Common(); |
128 | $this->setFrontendObject($ui); |
128 | $this->setFrontendObject($ui); |
129 | $this->debug = $this->config->get('verbose'); |
129 | $this->debug = $this->config->get('verbose'); |
130 | }
|
130 | }
|
131 | 131 | ||
132 | function setOptions($options) |
132 | function setOptions($options) |
133 | {
|
133 | {
|
134 | $this->_options = $options; |
134 | $this->_options = $options; |
135 | }
|
135 | }
|
136 | 136 | ||
137 | function setConfig(&$config) |
137 | function setConfig(&$config) |
138 | {
|
138 | {
|
139 | $this->config = &$config; |
139 | $this->config = &$config; |
140 | $this->_registry = &$config->getRegistry(); |
140 | $this->_registry = &$config->getRegistry(); |
141 | }
|
141 | }
|
142 | 142 | ||
143 | // }}}
|
143 | // }}}
|
144 | 144 | ||
145 | function _removeBackups($files) |
145 | function _removeBackups($files) |
146 | {
|
146 | {
|
147 | foreach ($files as $path) { |
147 | foreach ($files as $path) { |
148 | $this->addFileOperation('removebackup', array($path)); |
148 | $this->addFileOperation('removebackup', array($path)); |
149 | }
|
149 | }
|
150 | }
|
150 | }
|
151 | 151 | ||
152 | // {{{ _deletePackageFiles()
|
152 | // {{{ _deletePackageFiles()
|
153 | 153 | ||
154 | /**
|
154 | /**
|
155 | * Delete a package's installed files, does not remove empty directories.
|
155 | * Delete a package's installed files, does not remove empty directories.
|
156 | *
|
156 | *
|
157 | * @param string package name
|
157 | * @param string package name
|
158 | * @param string channel name
|
158 | * @param string channel name
|
159 | * @param bool if true, then files are backed up first
|
159 | * @param bool if true, then files are backed up first
|
160 | * @return bool TRUE on success, or a PEAR error on failure
|
160 | * @return bool TRUE on success, or a PEAR error on failure
|
161 | * @access protected
|
161 | * @access protected
|
162 | */
|
162 | */
|
163 | function _deletePackageFiles($package, $channel = false, $backup = false) |
163 | function _deletePackageFiles($package, $channel = false, $backup = false) |
164 | {
|
164 | {
|
165 | if (!$channel) { |
165 | if (!$channel) { |
166 | $channel = 'pear.php.net'; |
166 | $channel = 'pear.php.net'; |
167 | }
|
167 | }
|
168 | if (!strlen($package)) { |
168 | if (!strlen($package)) { |
169 | return $this->raiseError("No package to uninstall given"); |
169 | return $this->raiseError("No package to uninstall given"); |
170 | }
|
170 | }
|
171 | if (strtolower($package) == 'pear' && $channel == 'pear.php.net') { |
171 | if (strtolower($package) == 'pear' && $channel == 'pear.php.net') { |
172 | // to avoid race conditions, include all possible needed files
|
172 | // to avoid race conditions, include all possible needed files
|
173 | require_once 'PEAR/Task/Common.php'; |
173 | require_once 'PEAR/Task/Common.php'; |
174 | require_once 'PEAR/Task/Replace.php'; |
174 | require_once 'PEAR/Task/Replace.php'; |
175 | require_once 'PEAR/Task/Unixeol.php'; |
175 | require_once 'PEAR/Task/Unixeol.php'; |
176 | require_once 'PEAR/Task/Windowseol.php'; |
176 | require_once 'PEAR/Task/Windowseol.php'; |
177 | require_once 'PEAR/PackageFile/v1.php'; |
177 | require_once 'PEAR/PackageFile/v1.php'; |
178 | require_once 'PEAR/PackageFile/v2.php'; |
178 | require_once 'PEAR/PackageFile/v2.php'; |
179 | require_once 'PEAR/PackageFile/Generator/v1.php'; |
179 | require_once 'PEAR/PackageFile/Generator/v1.php'; |
180 | require_once 'PEAR/PackageFile/Generator/v2.php'; |
180 | require_once 'PEAR/PackageFile/Generator/v2.php'; |
181 | }
|
181 | }
|
182 | $filelist = $this->_registry->packageInfo($package, 'filelist', $channel); |
182 | $filelist = $this->_registry->packageInfo($package, 'filelist', $channel); |
183 | if ($filelist == null) { |
183 | if ($filelist == null) { |
184 | return $this->raiseError("$channel/$package not installed"); |
184 | return $this->raiseError("$channel/$package not installed"); |
185 | }
|
185 | }
|
186 | $ret = array(); |
186 | $ret = array(); |
187 | foreach ($filelist as $file => $props) { |
187 | foreach ($filelist as $file => $props) { |
188 | if (empty($props['installed_as'])) { |
188 | if (empty($props['installed_as'])) { |
189 | continue; |
189 | continue; |
190 | }
|
190 | }
|
191 | $path = $props['installed_as']; |
191 | $path = $props['installed_as']; |
192 | if ($backup) { |
192 | if ($backup) { |
193 | $this->addFileOperation('backup', array($path)); |
193 | $this->addFileOperation('backup', array($path)); |
194 | $ret[] = $path; |
194 | $ret[] = $path; |
195 | }
|
195 | }
|
196 | $this->addFileOperation('delete', array($path)); |
196 | $this->addFileOperation('delete', array($path)); |
197 | }
|
197 | }
|
198 | if ($backup) { |
198 | if ($backup) { |
199 | return $ret; |
199 | return $ret; |
200 | }
|
200 | }
|
201 | return true; |
201 | return true; |
202 | }
|
202 | }
|
203 | 203 | ||
204 | // }}}
|
204 | // }}}
|
205 | // {{{ _installFile()
|
205 | // {{{ _installFile()
|
206 | 206 | ||
207 | /**
|
207 | /**
|
208 | * @param string filename
|
208 | * @param string filename
|
209 | * @param array attributes from <file> tag in package.xml
|
209 | * @param array attributes from <file> tag in package.xml
|
210 | * @param string path to install the file in
|
210 | * @param string path to install the file in
|
211 | * @param array options from command-line
|
211 | * @param array options from command-line
|
212 | * @access private
|
212 | * @access private
|
213 | */
|
213 | */
|
214 | function _installFile($file, $atts, $tmp_path, $options) |
214 | function _installFile($file, $atts, $tmp_path, $options) |
215 | {
|
215 | {
|
216 | // {{{ return if this file is meant for another platform
|
216 | // {{{ return if this file is meant for another platform
|
217 | static $os; |
217 | static $os; |
218 | if (!isset($this->_registry)) { |
218 | if (!isset($this->_registry)) { |
219 | $this->_registry = &$this->config->getRegistry(); |
219 | $this->_registry = &$this->config->getRegistry(); |
220 | }
|
220 | }
|
221 | if (isset($atts['platform'])) { |
221 | if (isset($atts['platform'])) { |
222 | if (empty($os)) { |
222 | if (empty($os)) { |
223 | $os = new OS_Guess(); |
223 | $os = new OS_Guess(); |
224 | }
|
224 | }
|
225 | if (strlen($atts['platform']) && $atts['platform']{0} == '!') { |
225 | if (strlen($atts['platform']) && $atts['platform']{0} == '!') { |
226 | $negate = true; |
226 | $negate = true; |
227 | $platform = substr($atts['platform'], 1); |
227 | $platform = substr($atts['platform'], 1); |
228 | } else { |
228 | } else { |
229 | $negate = false; |
229 | $negate = false; |
230 | $platform = $atts['platform']; |
230 | $platform = $atts['platform']; |
231 | }
|
231 | }
|
232 | if ((bool) $os->matchSignature($platform) === $negate) { |
232 | if ((bool) $os->matchSignature($platform) === $negate) { |
233 | $this->log(3, "skipped $file (meant for $atts[platform], we are ".$os->getSignature().")"); |
233 | $this->log(3, "skipped $file (meant for $atts[platform], we are ".$os->getSignature().")"); |
234 | return PEAR_INSTALLER_SKIPPED; |
234 | return PEAR_INSTALLER_SKIPPED; |
235 | }
|
235 | }
|
236 | }
|
236 | }
|
237 | // }}}
|
237 | // }}}
|
238 | 238 | ||
239 | $channel = $this->pkginfo->getChannel(); |
239 | $channel = $this->pkginfo->getChannel(); |
240 | // {{{ assemble the destination paths
|
240 | // {{{ assemble the destination paths
|
241 | switch ($atts['role']) { |
241 | switch ($atts['role']) { |
242 | case 'src': |
242 | case 'src': |
243 | case 'extsrc': |
243 | case 'extsrc': |
244 | $this->source_files++; |
244 | $this->source_files++; |
245 | return; |
245 | return; |
246 | case 'doc': |
246 | case 'doc': |
247 | case 'data': |
247 | case 'data': |
248 | case 'test': |
248 | case 'test': |
249 | $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel) . |
249 | $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel) . |
250 | DIRECTORY_SEPARATOR . $this->pkginfo->getPackage(); |
250 | DIRECTORY_SEPARATOR . $this->pkginfo->getPackage(); |
251 | unset($atts['baseinstalldir']); |
251 | unset($atts['baseinstalldir']); |
252 | break; |
252 | break; |
253 | case 'ext': |
253 | case 'ext': |
254 | case 'php': |
254 | case 'php': |
255 | $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel); |
255 | $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel); |
256 | break; |
256 | break; |
257 | case 'script': |
257 | case 'script': |
258 | $dest_dir = $this->config->get('bin_dir', null, $channel); |
258 | $dest_dir = $this->config->get('bin_dir', null, $channel); |
259 | break; |
259 | break; |
260 | default: |
260 | default: |
261 | return $this->raiseError("Invalid role `$atts[role]' for file $file"); |
261 | return $this->raiseError("Invalid role `$atts[role]' for file $file"); |
262 | }
|
262 | }
|
263 | $save_destdir = $dest_dir; |
263 | $save_destdir = $dest_dir; |
264 | if (!empty($atts['baseinstalldir'])) { |
264 | if (!empty($atts['baseinstalldir'])) { |
265 | $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir']; |
265 | $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir']; |
266 | }
|
266 | }
|
267 | if (dirname($file) != '.' && empty($atts['install-as'])) { |
267 | if (dirname($file) != '.' && empty($atts['install-as'])) { |
268 | $dest_dir .= DIRECTORY_SEPARATOR . dirname($file); |
268 | $dest_dir .= DIRECTORY_SEPARATOR . dirname($file); |
269 | }
|
269 | }
|
270 | if (empty($atts['install-as'])) { |
270 | if (empty($atts['install-as'])) { |
271 | $dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file); |
271 | $dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file); |
272 | } else { |
272 | } else { |
273 | $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as']; |
273 | $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as']; |
274 | }
|
274 | }
|
275 | $orig_file = $tmp_path . DIRECTORY_SEPARATOR . $file; |
275 | $orig_file = $tmp_path . DIRECTORY_SEPARATOR . $file; |
276 | 276 | ||
277 | // Clean up the DIRECTORY_SEPARATOR mess
|
277 | // Clean up the DIRECTORY_SEPARATOR mess
|
278 | $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR; |
278 | $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR; |
279 | list($dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"), |
279 | list($dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"), |
280 | array(DIRECTORY_SEPARATOR, |
280 | array(DIRECTORY_SEPARATOR, |
281 | DIRECTORY_SEPARATOR, |
281 | DIRECTORY_SEPARATOR, |
282 | DIRECTORY_SEPARATOR), |
282 | DIRECTORY_SEPARATOR), |
283 | array($dest_file, $orig_file)); |
283 | array($dest_file, $orig_file)); |
284 | $final_dest_file = $installed_as = $dest_file; |
284 | $final_dest_file = $installed_as = $dest_file; |
285 | if (isset($this->_options['packagingroot'])) { |
285 | if (isset($this->_options['packagingroot'])) { |
286 | $installedas_dest_dir = dirname($final_dest_file); |
286 | $installedas_dest_dir = dirname($final_dest_file); |
287 | $installedas_dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); |
287 | $installedas_dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); |
288 | $final_dest_file = $this->_prependPath($final_dest_file, |
288 | $final_dest_file = $this->_prependPath($final_dest_file, |
289 | $this->_options['packagingroot']); |
289 | $this->_options['packagingroot']); |
290 | } else { |
290 | } else { |
291 | $installedas_dest_dir = dirname($final_dest_file); |
291 | $installedas_dest_dir = dirname($final_dest_file); |
292 | $installedas_dest_file = $installedas_dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); |
292 | $installedas_dest_file = $installedas_dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); |
293 | }
|
293 | }
|
294 | $dest_dir = dirname($final_dest_file); |
294 | $dest_dir = dirname($final_dest_file); |
295 | $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); |
295 | $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); |
296 | if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file))) { |
296 | if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file))) { |
297 | return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED); |
297 | return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED); |
298 | }
|
298 | }
|
299 | // }}}
|
299 | // }}}
|
300 | 300 | ||
301 | if (empty($this->_options['register-only']) && |
301 | if (empty($this->_options['register-only']) && |
302 | (!file_exists($dest_dir) || !is_dir($dest_dir))) { |
302 | (!file_exists($dest_dir) || !is_dir($dest_dir))) { |
303 | if (!$this->mkDirHier($dest_dir)) { |
303 | if (!$this->mkDirHier($dest_dir)) { |
304 | return $this->raiseError("failed to mkdir $dest_dir", |
304 | return $this->raiseError("failed to mkdir $dest_dir", |
305 | PEAR_INSTALLER_FAILED); |
305 | PEAR_INSTALLER_FAILED); |
306 | }
|
306 | }
|
307 | $this->log(3, "+ mkdir $dest_dir"); |
307 | $this->log(3, "+ mkdir $dest_dir"); |
308 | }
|
308 | }
|
309 | // pretty much nothing happens if we are only registering the install
|
309 | // pretty much nothing happens if we are only registering the install
|
310 | if (empty($this->_options['register-only'])) { |
310 | if (empty($this->_options['register-only'])) { |
311 | if (empty($atts['replacements'])) { |
311 | if (empty($atts['replacements'])) { |
312 | if (!file_exists($orig_file)) { |
312 | if (!file_exists($orig_file)) { |
313 | return $this->raiseError("file $orig_file does not exist", |
313 | return $this->raiseError("file $orig_file does not exist", |
314 | PEAR_INSTALLER_FAILED); |
314 | PEAR_INSTALLER_FAILED); |
315 | }
|
315 | }
|
316 | if (!@copy($orig_file, $dest_file)) { |
316 | if (!@copy($orig_file, $dest_file)) { |
317 | return $this->raiseError("failed to write $dest_file: $php_errormsg", |
317 | return $this->raiseError("failed to write $dest_file: $php_errormsg", |
318 | PEAR_INSTALLER_FAILED); |
318 | PEAR_INSTALLER_FAILED); |
319 | }
|
319 | }
|
320 | $this->log(3, "+ cp $orig_file $dest_file"); |
320 | $this->log(3, "+ cp $orig_file $dest_file"); |
321 | if (isset($atts['md5sum'])) { |
321 | if (isset($atts['md5sum'])) { |
322 | $md5sum = md5_file($dest_file); |
322 | $md5sum = md5_file($dest_file); |
323 | }
|
323 | }
|
324 | } else { |
324 | } else { |
325 | // {{{ file with replacements
|
325 | // {{{ file with replacements
|
326 | if (!file_exists($orig_file)) { |
326 | if (!file_exists($orig_file)) { |
327 | return $this->raiseError("file does not exist", |
327 | return $this->raiseError("file does not exist", |
328 | PEAR_INSTALLER_FAILED); |
328 | PEAR_INSTALLER_FAILED); |
329 | }
|
329 | }
|
330 | $contents = file_get_contents($orig_file); |
330 | $contents = file_get_contents($orig_file); |
331 | if ($contents === false) { |
331 | if ($contents === false) { |
332 | $contents = ''; |
332 | $contents = ''; |
333 | }
|
333 | }
|
334 | if (isset($atts['md5sum'])) { |
334 | if (isset($atts['md5sum'])) { |
335 | $md5sum = md5($contents); |
335 | $md5sum = md5($contents); |
336 | }
|
336 | }
|
337 | $subst_from = $subst_to = array(); |
337 | $subst_from = $subst_to = array(); |
338 | foreach ($atts['replacements'] as $a) { |
338 | foreach ($atts['replacements'] as $a) { |
339 | $to = ''; |
339 | $to = ''; |
340 | if ($a['type'] == 'php-const') { |
340 | if ($a['type'] == 'php-const') { |
341 | if (preg_match('/^[a-z0-9_]+\\z/i', $a['to'])) { |
341 | if (preg_match('/^[a-z0-9_]+\\z/i', $a['to'])) { |
342 | eval("\$to = $a[to];"); |
342 | eval("\$to = $a[to];"); |
343 | } else { |
343 | } else { |
344 | if (!isset($options['soft'])) { |
344 | if (!isset($options['soft'])) { |
345 | $this->log(0, "invalid php-const replacement: $a[to]"); |
345 | $this->log(0, "invalid php-const replacement: $a[to]"); |
346 | }
|
346 | }
|
347 | continue; |
347 | continue; |
348 | }
|
348 | }
|
349 | } elseif ($a['type'] == 'pear-config') { |
349 | } elseif ($a['type'] == 'pear-config') { |
350 | if ($a['to'] == 'master_server') { |
350 | if ($a['to'] == 'master_server') { |
351 | $chan = $this->_registry->getChannel($channel); |
351 | $chan = $this->_registry->getChannel($channel); |
352 | if (!PEAR::isError($chan)) { |
352 | if (!PEAR::isError($chan)) { |
353 | $to = $chan->getServer(); |
353 | $to = $chan->getServer(); |
354 | } else { |
354 | } else { |
355 | $to = $this->config->get($a['to'], null, $channel); |
355 | $to = $this->config->get($a['to'], null, $channel); |
356 | }
|
356 | }
|
357 | } else { |
357 | } else { |
358 | $to = $this->config->get($a['to'], null, $channel); |
358 | $to = $this->config->get($a['to'], null, $channel); |
359 | }
|
359 | }
|
360 | if (is_null($to)) { |
360 | if (is_null($to)) { |
361 | if (!isset($options['soft'])) { |
361 | if (!isset($options['soft'])) { |
362 | $this->log(0, "invalid pear-config replacement: $a[to]"); |
362 | $this->log(0, "invalid pear-config replacement: $a[to]"); |
363 | }
|
363 | }
|
364 | continue; |
364 | continue; |
365 | }
|
365 | }
|
366 | } elseif ($a['type'] == 'package-info') { |
366 | } elseif ($a['type'] == 'package-info') { |
367 | if ($t = $this->pkginfo->packageInfo($a['to'])) { |
367 | if ($t = $this->pkginfo->packageInfo($a['to'])) { |
368 | $to = $t; |
368 | $to = $t; |
369 | } else { |
369 | } else { |
370 | if (!isset($options['soft'])) { |
370 | if (!isset($options['soft'])) { |
371 | $this->log(0, "invalid package-info replacement: $a[to]"); |
371 | $this->log(0, "invalid package-info replacement: $a[to]"); |
372 | }
|
372 | }
|
373 | continue; |
373 | continue; |
374 | }
|
374 | }
|
375 | }
|
375 | }
|
376 | if (!is_null($to)) { |
376 | if (!is_null($to)) { |
377 | $subst_from[] = $a['from']; |
377 | $subst_from[] = $a['from']; |
378 | $subst_to[] = $to; |
378 | $subst_to[] = $to; |
379 | }
|
379 | }
|
380 | }
|
380 | }
|
381 | $this->log(3, "doing ".sizeof($subst_from)." substitution(s) for $final_dest_file"); |
381 | $this->log(3, "doing ".sizeof($subst_from)." substitution(s) for $final_dest_file"); |
382 | if (sizeof($subst_from)) { |
382 | if (sizeof($subst_from)) { |
383 | $contents = str_replace($subst_from, $subst_to, $contents); |
383 | $contents = str_replace($subst_from, $subst_to, $contents); |
384 | }
|
384 | }
|
385 | $wp = @fopen($dest_file, "wb"); |
385 | $wp = @fopen($dest_file, "wb"); |
386 | if (!is_resource($wp)) { |
386 | if (!is_resource($wp)) { |
387 | return $this->raiseError("failed to create $dest_file: $php_errormsg", |
387 | return $this->raiseError("failed to create $dest_file: $php_errormsg", |
388 | PEAR_INSTALLER_FAILED); |
388 | PEAR_INSTALLER_FAILED); |
389 | }
|
389 | }
|
390 | if (@fwrite($wp, $contents) === false) { |
390 | if (@fwrite($wp, $contents) === false) { |
391 | return $this->raiseError("failed writing to $dest_file: $php_errormsg", |
391 | return $this->raiseError("failed writing to $dest_file: $php_errormsg", |
392 | PEAR_INSTALLER_FAILED); |
392 | PEAR_INSTALLER_FAILED); |
393 | }
|
393 | }
|
394 | fclose($wp); |
394 | fclose($wp); |
395 | // }}}
|
395 | // }}}
|
396 | }
|
396 | }
|
397 | // {{{ check the md5
|
397 | // {{{ check the md5
|
398 | if (isset($md5sum)) { |
398 | if (isset($md5sum)) { |
399 | if (strtolower($md5sum) === strtolower($atts['md5sum'])) { |
399 | if (strtolower($md5sum) === strtolower($atts['md5sum'])) { |
400 | $this->log(2, "md5sum ok: $final_dest_file"); |
400 | $this->log(2, "md5sum ok: $final_dest_file"); |
401 | } else { |
401 | } else { |
402 | if (empty($options['force'])) { |
402 | if (empty($options['force'])) { |
403 | // delete the file
|
403 | // delete the file
|
404 | if (file_exists($dest_file)) { |
404 | if (file_exists($dest_file)) { |
405 | unlink($dest_file); |
405 | unlink($dest_file); |
406 | }
|
406 | }
|
407 | if (!isset($options['ignore-errors'])) { |
407 | if (!isset($options['ignore-errors'])) { |
408 | return $this->raiseError("bad md5sum for file $final_dest_file", |
408 | return $this->raiseError("bad md5sum for file $final_dest_file", |
409 | PEAR_INSTALLER_FAILED); |
409 | PEAR_INSTALLER_FAILED); |
410 | } else { |
410 | } else { |
411 | if (!isset($options['soft'])) { |
411 | if (!isset($options['soft'])) { |
412 | $this->log(0, "warning : bad md5sum for file $final_dest_file"); |
412 | $this->log(0, "warning : bad md5sum for file $final_dest_file"); |
413 | }
|
413 | }
|
414 | }
|
414 | }
|
415 | } else { |
415 | } else { |
416 | if (!isset($options['soft'])) { |
416 | if (!isset($options['soft'])) { |
417 | $this->log(0, "warning : bad md5sum for file $final_dest_file"); |
417 | $this->log(0, "warning : bad md5sum for file $final_dest_file"); |
418 | }
|
418 | }
|
419 | }
|
419 | }
|
420 | }
|
420 | }
|
421 | }
|
421 | }
|
422 | // }}}
|
422 | // }}}
|
423 | // {{{ set file permissions
|
423 | // {{{ set file permissions
|
424 | if (!OS_WINDOWS) { |
424 | if (!OS_WINDOWS) { |
425 | if ($atts['role'] == 'script') { |
425 | if ($atts['role'] == 'script') { |
426 | $mode = 0777 & ~(int)octdec($this->config->get('umask')); |
426 | $mode = 0777 & ~(int)octdec($this->config->get('umask')); |
427 | $this->log(3, "+ chmod +x $dest_file"); |
427 | $this->log(3, "+ chmod +x $dest_file"); |
428 | } else { |
428 | } else { |
429 | $mode = 0666 & ~(int)octdec($this->config->get('umask')); |
429 | $mode = 0666 & ~(int)octdec($this->config->get('umask')); |
430 | }
|
430 | }
|
431 | if ($atts['role'] != 'src') { |
431 | if ($atts['role'] != 'src') { |
432 | $this->addFileOperation("chmod", array($mode, $dest_file)); |
432 | $this->addFileOperation("chmod", array($mode, $dest_file)); |
433 | if (!@chmod($dest_file, $mode)) { |
433 | if (!@chmod($dest_file, $mode)) { |
434 | if (!isset($options['soft'])) { |
434 | if (!isset($options['soft'])) { |
435 | $this->log(0, "failed to change mode of $dest_file: $php_errormsg"); |
435 | $this->log(0, "failed to change mode of $dest_file: $php_errormsg"); |
436 | }
|
436 | }
|
437 | }
|
437 | }
|
438 | }
|
438 | }
|
439 | }
|
439 | }
|
440 | // }}}
|
440 | // }}}
|
441 | if ($atts['role'] == 'src') { |
441 | if ($atts['role'] == 'src') { |
442 | rename($dest_file, $final_dest_file); |
442 | rename($dest_file, $final_dest_file); |
443 | $this->log(2, "renamed source file $dest_file to $final_dest_file"); |
443 | $this->log(2, "renamed source file $dest_file to $final_dest_file"); |
444 | } else { |
444 | } else { |
445 | $this->addFileOperation("rename", array($dest_file, $final_dest_file, |
445 | $this->addFileOperation("rename", array($dest_file, $final_dest_file, |
446 | $atts['role'] == 'ext')); |
446 | $atts['role'] == 'ext')); |
447 | }
|
447 | }
|
448 | }
|
448 | }
|
449 | // Store the full path where the file was installed for easy unistall
|
449 | // Store the full path where the file was installed for easy unistall
|
450 | if ($atts['role'] != 'script') { |
450 | if ($atts['role'] != 'script') { |
451 | $loc = $this->config->get($atts['role'] . '_dir'); |
451 | $loc = $this->config->get($atts['role'] . '_dir'); |
452 | } else { |
452 | } else { |
453 | $loc = $this->config->get('bin_dir'); |
453 | $loc = $this->config->get('bin_dir'); |
454 | }
|
454 | }
|
455 | if ($atts['role'] != 'src') { |
455 | if ($atts['role'] != 'src') { |
456 | $this->addFileOperation("installed_as", array($file, $installed_as, |
456 | $this->addFileOperation("installed_as", array($file, $installed_as, |
457 | $loc, |
457 | $loc, |
458 | dirname(substr($installedas_dest_file, strlen($loc))))); |
458 | dirname(substr($installedas_dest_file, strlen($loc))))); |
459 | }
|
459 | }
|
460 | 460 | ||
461 | //$this->log(2, "installed: $dest_file");
|
461 | //$this->log(2, "installed: $dest_file");
|
462 | return PEAR_INSTALLER_OK; |
462 | return PEAR_INSTALLER_OK; |
463 | }
|
463 | }
|
464 | 464 | ||
465 | // }}}
|
465 | // }}}
|
466 | // {{{ _installFile2()
|
466 | // {{{ _installFile2()
|
467 | 467 | ||
468 | /**
|
468 | /**
|
469 | * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
|
469 | * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
|
470 | * @param string filename
|
470 | * @param string filename
|
471 | * @param array attributes from <file> tag in package.xml
|
471 | * @param array attributes from <file> tag in package.xml
|
472 | * @param string path to install the file in
|
472 | * @param string path to install the file in
|
473 | * @param array options from command-line
|
473 | * @param array options from command-line
|
474 | * @access private
|
474 | * @access private
|
475 | */
|
475 | */
|
476 | function _installFile2(&$pkg, $file, &$real_atts, $tmp_path, $options) |
476 | function _installFile2(&$pkg, $file, &$real_atts, $tmp_path, $options) |
477 | {
|
477 | {
|
478 | $atts = $real_atts; |
478 | $atts = $real_atts; |
479 | if (!isset($this->_registry)) { |
479 | if (!isset($this->_registry)) { |
480 | $this->_registry = &$this->config->getRegistry(); |
480 | $this->_registry = &$this->config->getRegistry(); |
481 | }
|
481 | }
|
482 | 482 | ||
483 | $channel = $pkg->getChannel(); |
483 | $channel = $pkg->getChannel(); |
484 | // {{{ assemble the destination paths
|
484 | // {{{ assemble the destination paths
|
485 | if (!in_array($atts['attribs']['role'], |
485 | if (!in_array($atts['attribs']['role'], |
486 | PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) { |
486 | PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) { |
487 | return $this->raiseError('Invalid role `' . $atts['attribs']['role'] . |
487 | return $this->raiseError('Invalid role `' . $atts['attribs']['role'] . |
488 | "' for file $file"); |
488 | "' for file $file"); |
489 | }
|
489 | }
|
490 | $role = &PEAR_Installer_Role::factory($pkg, $atts['attribs']['role'], $this->config); |
490 | $role = &PEAR_Installer_Role::factory($pkg, $atts['attribs']['role'], $this->config); |
491 | $err = $role->setup($this, $pkg, $atts['attribs'], $file); |
491 | $err = $role->setup($this, $pkg, $atts['attribs'], $file); |
492 | if (PEAR::isError($err)) { |
492 | if (PEAR::isError($err)) { |
493 | return $err; |
493 | return $err; |
494 | }
|
494 | }
|
495 | if (!$role->isInstallable()) { |
495 | if (!$role->isInstallable()) { |
496 | return; |
496 | return; |
497 | }
|
497 | }
|
498 | $info = $role->processInstallation($pkg, $atts['attribs'], $file, $tmp_path); |
498 | $info = $role->processInstallation($pkg, $atts['attribs'], $file, $tmp_path); |
499 | if (PEAR::isError($info)) { |
499 | if (PEAR::isError($info)) { |
500 | return $info; |
500 | return $info; |
501 | } else { |
501 | } else { |
502 | list($save_destdir, $dest_dir, $dest_file, $orig_file) = $info; |
502 | list($save_destdir, $dest_dir, $dest_file, $orig_file) = $info; |
503 | }
|
503 | }
|
504 | if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file))) { |
504 | if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file))) { |
505 | return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED); |
505 | return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED); |
506 | }
|
506 | }
|
507 | $final_dest_file = $installed_as = $dest_file; |
507 | $final_dest_file = $installed_as = $dest_file; |
508 | if (isset($this->_options['packagingroot'])) { |
508 | if (isset($this->_options['packagingroot'])) { |
509 | $final_dest_file = $this->_prependPath($final_dest_file, |
509 | $final_dest_file = $this->_prependPath($final_dest_file, |
510 | $this->_options['packagingroot']); |
510 | $this->_options['packagingroot']); |
511 | }
|
511 | }
|
512 | $dest_dir = dirname($final_dest_file); |
512 | $dest_dir = dirname($final_dest_file); |
513 | $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); |
513 | $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); |
514 | // }}}
|
514 | // }}}
|
515 | 515 | ||
516 | if (empty($this->_options['register-only'])) { |
516 | if (empty($this->_options['register-only'])) { |
517 | if (!file_exists($dest_dir) || !is_dir($dest_dir)) { |
517 | if (!file_exists($dest_dir) || !is_dir($dest_dir)) { |
518 | if (!$this->mkDirHier($dest_dir)) { |
518 | if (!$this->mkDirHier($dest_dir)) { |
519 | return $this->raiseError("failed to mkdir $dest_dir", |
519 | return $this->raiseError("failed to mkdir $dest_dir", |
520 | PEAR_INSTALLER_FAILED); |
520 | PEAR_INSTALLER_FAILED); |
521 | }
|
521 | }
|
522 | $this->log(3, "+ mkdir $dest_dir"); |
522 | $this->log(3, "+ mkdir $dest_dir"); |
523 | }
|
523 | }
|
524 | }
|
524 | }
|
525 | $attribs = $atts['attribs']; |
525 | $attribs = $atts['attribs']; |
526 | unset($atts['attribs']); |
526 | unset($atts['attribs']); |
527 | // pretty much nothing happens if we are only registering the install
|
527 | // pretty much nothing happens if we are only registering the install
|
528 | if (empty($this->_options['register-only'])) { |
528 | if (empty($this->_options['register-only'])) { |
529 | if (!count($atts)) { // no tasks |
529 | if (!count($atts)) { // no tasks |
530 | if (!file_exists($orig_file)) { |
530 | if (!file_exists($orig_file)) { |
531 | return $this->raiseError("file $orig_file does not exist", |
531 | return $this->raiseError("file $orig_file does not exist", |
532 | PEAR_INSTALLER_FAILED); |
532 | PEAR_INSTALLER_FAILED); |
533 | }
|
533 | }
|
534 | if (!@copy($orig_file, $dest_file)) { |
534 | if (!@copy($orig_file, $dest_file)) { |
535 | return $this->raiseError("failed to write $dest_file: $php_errormsg", |
535 | return $this->raiseError("failed to write $dest_file: $php_errormsg", |
536 | PEAR_INSTALLER_FAILED); |
536 | PEAR_INSTALLER_FAILED); |
537 | }
|
537 | }
|
538 | $this->log(3, "+ cp $orig_file $dest_file"); |
538 | $this->log(3, "+ cp $orig_file $dest_file"); |
539 | if (isset($attribs['md5sum'])) { |
539 | if (isset($attribs['md5sum'])) { |
540 | $md5sum = md5_file($dest_file); |
540 | $md5sum = md5_file($dest_file); |
541 | }
|
541 | }
|
542 | } else { // file with tasks |
542 | } else { // file with tasks |
543 | if (!file_exists($orig_file)) { |
543 | if (!file_exists($orig_file)) { |
544 | return $this->raiseError("file $orig_file does not exist", |
544 | return $this->raiseError("file $orig_file does not exist", |
545 | PEAR_INSTALLER_FAILED); |
545 | PEAR_INSTALLER_FAILED); |
546 | }
|
546 | }
|
547 | $contents = file_get_contents($orig_file); |
547 | $contents = file_get_contents($orig_file); |
548 | if ($contents === false) { |
548 | if ($contents === false) { |
549 | $contents = ''; |
549 | $contents = ''; |
550 | }
|
550 | }
|
551 | if (isset($attribs['md5sum'])) { |
551 | if (isset($attribs['md5sum'])) { |
552 | $md5sum = md5($contents); |
552 | $md5sum = md5($contents); |
553 | }
|
553 | }
|
554 | foreach ($atts as $tag => $raw) { |
554 | foreach ($atts as $tag => $raw) { |
555 | $tag = str_replace(array($pkg->getTasksNs() . ':', '-'), |
555 | $tag = str_replace(array($pkg->getTasksNs() . ':', '-'), |
556 | array('', '_'), $tag); |
556 | array('', '_'), $tag); |
557 | $task = "PEAR_Task_$tag"; |
557 | $task = "PEAR_Task_$tag"; |
558 | $task = &new $task($this->config, $this, PEAR_TASK_INSTALL); |
558 | $task = &new $task($this->config, $this, PEAR_TASK_INSTALL); |
559 | if (!$task->isScript()) { // scripts are only handled after installation |
559 | if (!$task->isScript()) { // scripts are only handled after installation |
560 | $task->init($raw, $attribs, $pkg->getLastInstalledVersion()); |
560 | $task->init($raw, $attribs, $pkg->getLastInstalledVersion()); |
561 | $res = $task->startSession($pkg, $contents, $final_dest_file); |
561 | $res = $task->startSession($pkg, $contents, $final_dest_file); |
562 | if ($res === false) { |
562 | if ($res === false) { |
563 | continue; // skip this file |
563 | continue; // skip this file |
564 | }
|
564 | }
|
565 | if (PEAR::isError($res)) { |
565 | if (PEAR::isError($res)) { |
566 | return $res; |
566 | return $res; |
567 | }
|
567 | }
|
568 | $contents = $res; // save changes |
568 | $contents = $res; // save changes |
569 | }
|
569 | }
|
570 | $wp = @fopen($dest_file, "wb"); |
570 | $wp = @fopen($dest_file, "wb"); |
571 | if (!is_resource($wp)) { |
571 | if (!is_resource($wp)) { |
572 | return $this->raiseError("failed to create $dest_file: $php_errormsg", |
572 | return $this->raiseError("failed to create $dest_file: $php_errormsg", |
573 | PEAR_INSTALLER_FAILED); |
573 | PEAR_INSTALLER_FAILED); |
574 | }
|
574 | }
|
575 | if (fwrite($wp, $contents) === false) { |
575 | if (fwrite($wp, $contents) === false) { |
576 | return $this->raiseError("failed writing to $dest_file: $php_errormsg", |
576 | return $this->raiseError("failed writing to $dest_file: $php_errormsg", |
577 | PEAR_INSTALLER_FAILED); |
577 | PEAR_INSTALLER_FAILED); |
578 | }
|
578 | }
|
579 | fclose($wp); |
579 | fclose($wp); |
580 | }
|
580 | }
|
581 | }
|
581 | }
|
582 | // {{{ check the md5
|
582 | // {{{ check the md5
|
583 | if (isset($md5sum)) { |
583 | if (isset($md5sum)) { |
584 | if (strtolower($md5sum) === strtolower($attribs['md5sum'])) { |
584 | if (strtolower($md5sum) === strtolower($attribs['md5sum'])) { |
585 | $this->log(2, "md5sum ok: $final_dest_file"); |
585 | $this->log(2, "md5sum ok: $final_dest_file"); |
586 | } else { |
586 | } else { |
587 | if (empty($options['force'])) { |
587 | if (empty($options['force'])) { |
588 | // delete the file
|
588 | // delete the file
|
589 | if (file_exists($dest_file)) { |
589 | if (file_exists($dest_file)) { |
590 | unlink($dest_file); |
590 | unlink($dest_file); |
591 | }
|
591 | }
|
592 | if (!isset($options['ignore-errors'])) { |
592 | if (!isset($options['ignore-errors'])) { |
593 | return $this->raiseError("bad md5sum for file $final_dest_file", |
593 | return $this->raiseError("bad md5sum for file $final_dest_file", |
594 | PEAR_INSTALLER_FAILED); |
594 | PEAR_INSTALLER_FAILED); |
595 | } else { |
595 | } else { |
596 | if (!isset($options['soft'])) { |
596 | if (!isset($options['soft'])) { |
597 | $this->log(0, "warning : bad md5sum for file $final_dest_file"); |
597 | $this->log(0, "warning : bad md5sum for file $final_dest_file"); |
598 | }
|
598 | }
|
599 | }
|
599 | }
|
600 | } else { |
600 | } else { |
601 | if (!isset($options['soft'])) { |
601 | if (!isset($options['soft'])) { |
602 | $this->log(0, "warning : bad md5sum for file $final_dest_file"); |
602 | $this->log(0, "warning : bad md5sum for file $final_dest_file"); |
603 | }
|
603 | }
|
604 | }
|
604 | }
|
605 | }
|
605 | }
|
606 | } else { |
606 | } else { |
607 | $real_atts['attribs']['md5sum'] = md5_file($dest_file); |
607 | $real_atts['attribs']['md5sum'] = md5_file($dest_file); |
608 | }
|
608 | }
|
609 | // }}}
|
609 | // }}}
|
610 | // {{{ set file permissions
|
610 | // {{{ set file permissions
|
611 | if (!OS_WINDOWS) { |
611 | if (!OS_WINDOWS) { |
612 | if ($role->isExecutable()) { |
612 | if ($role->isExecutable()) { |
613 | $mode = 0777 & ~(int)octdec($this->config->get('umask')); |
613 | $mode = 0777 & ~(int)octdec($this->config->get('umask')); |
614 | $this->log(3, "+ chmod +x $dest_file"); |
614 | $this->log(3, "+ chmod +x $dest_file"); |
615 | } else { |
615 | } else { |
616 | $mode = 0666 & ~(int)octdec($this->config->get('umask')); |
616 | $mode = 0666 & ~(int)octdec($this->config->get('umask')); |
617 | }
|
617 | }
|
618 | if ($attribs['role'] != 'src') { |
618 | if ($attribs['role'] != 'src') { |
619 | $this->addFileOperation("chmod", array($mode, $dest_file)); |
619 | $this->addFileOperation("chmod", array($mode, $dest_file)); |
620 | if (!@chmod($dest_file, $mode)) { |
620 | if (!@chmod($dest_file, $mode)) { |
621 | if (!isset($options['soft'])) { |
621 | if (!isset($options['soft'])) { |
622 | $this->log(0, "failed to change mode of $dest_file: $php_errormsg"); |
622 | $this->log(0, "failed to change mode of $dest_file: $php_errormsg"); |
623 | }
|
623 | }
|
624 | }
|
624 | }
|
625 | }
|
625 | }
|
626 | }
|
626 | }
|
627 | // }}}
|
627 | // }}}
|
628 | if ($attribs['role'] == 'src') { |
628 | if ($attribs['role'] == 'src') { |
629 | rename($dest_file, $final_dest_file); |
629 | rename($dest_file, $final_dest_file); |
630 | $this->log(2, "renamed source file $dest_file to $final_dest_file"); |
630 | $this->log(2, "renamed source file $dest_file to $final_dest_file"); |
631 | } else { |
631 | } else { |
632 | $this->addFileOperation("rename", array($dest_file, $final_dest_file, $role->isExtension())); |
632 | $this->addFileOperation("rename", array($dest_file, $final_dest_file, $role->isExtension())); |
633 | }
|
633 | }
|
634 | }
|
634 | }
|
635 | // Store the full path where the file was installed for easy uninstall
|
635 | // Store the full path where the file was installed for easy uninstall
|
636 | if ($attribs['role'] != 'src') { |
636 | if ($attribs['role'] != 'src') { |
637 | $loc = $this->config->get($role->getLocationConfig(), null, $channel); |
637 | $loc = $this->config->get($role->getLocationConfig(), null, $channel); |
638 | $this->addFileOperation("installed_as", array($file, $installed_as, |
638 | $this->addFileOperation("installed_as", array($file, $installed_as, |
639 | $loc, |
639 | $loc, |
640 | dirname(substr($installed_as, strlen($loc))))); |
640 | dirname(substr($installed_as, strlen($loc))))); |
641 | }
|
641 | }
|
642 | 642 | ||
643 | //$this->log(2, "installed: $dest_file");
|
643 | //$this->log(2, "installed: $dest_file");
|
644 | return PEAR_INSTALLER_OK; |
644 | return PEAR_INSTALLER_OK; |
645 | }
|
645 | }
|
646 | 646 | ||
647 | // }}}
|
647 | // }}}
|
648 | // {{{ addFileOperation()
|
648 | // {{{ addFileOperation()
|
649 | 649 | ||
650 | /**
|
650 | /**
|
651 | * Add a file operation to the current file transaction.
|
651 | * Add a file operation to the current file transaction.
|
652 | *
|
652 | *
|
653 | * @see startFileTransaction()
|
653 | * @see startFileTransaction()
|
654 | * @param string $type This can be one of:
|
654 | * @param string $type This can be one of:
|
655 | * - rename: rename a file ($data has 3 values)
|
655 | * - rename: rename a file ($data has 3 values)
|
656 | * - backup: backup an existing file ($data has 1 value)
|
656 | * - backup: backup an existing file ($data has 1 value)
|
657 | * - removebackup: clean up backups created during install ($data has 1 value)
|
657 | * - removebackup: clean up backups created during install ($data has 1 value)
|
658 | * - chmod: change permissions on a file ($data has 2 values)
|
658 | * - chmod: change permissions on a file ($data has 2 values)
|
659 | * - delete: delete a file ($data has 1 value)
|
659 | * - delete: delete a file ($data has 1 value)
|
660 | * - rmdir: delete a directory if empty ($data has 1 value)
|
660 | * - rmdir: delete a directory if empty ($data has 1 value)
|
661 | * - installed_as: mark a file as installed ($data has 4 values).
|
661 | * - installed_as: mark a file as installed ($data has 4 values).
|
662 | * @param array $data For all file operations, this array must contain the
|
662 | * @param array $data For all file operations, this array must contain the
|
663 | * full path to the file or directory that is being operated on. For
|
663 | * full path to the file or directory that is being operated on. For
|
664 | * the rename command, the first parameter must be the file to rename,
|
664 | * the rename command, the first parameter must be the file to rename,
|
665 | * the second its new name, the third whether this is a PHP extension.
|
665 | * the second its new name, the third whether this is a PHP extension.
|
666 | *
|
666 | *
|
667 | * The installed_as operation contains 4 elements in this order:
|
667 | * The installed_as operation contains 4 elements in this order:
|
668 | * 1. Filename as listed in the filelist element from package.xml
|
668 | * 1. Filename as listed in the filelist element from package.xml
|
669 | * 2. Full path to the installed file
|
669 | * 2. Full path to the installed file
|
670 | * 3. Full path from the php_dir configuration variable used in this
|
670 | * 3. Full path from the php_dir configuration variable used in this
|
671 | * installation
|
671 | * installation
|
672 | * 4. Relative path from the php_dir that this file is installed in
|
672 | * 4. Relative path from the php_dir that this file is installed in
|
673 | */
|
673 | */
|
674 | function addFileOperation($type, $data) |
674 | function addFileOperation($type, $data) |
675 | {
|
675 | {
|
676 | if (!is_array($data)) { |
676 | if (!is_array($data)) { |
677 | return $this->raiseError('Internal Error: $data in addFileOperation' |
677 | return $this->raiseError('Internal Error: $data in addFileOperation' |
678 | . ' must be an array, was ' . gettype($data)); |
678 | . ' must be an array, was ' . gettype($data)); |
679 | }
|
679 | }
|
680 | if ($type == 'chmod') { |
680 | if ($type == 'chmod') { |
681 | $octmode = decoct($data[0]); |
681 | $octmode = decoct($data[0]); |
682 | $this->log(3, "adding to transaction: $type $octmode $data[1]"); |
682 | $this->log(3, "adding to transaction: $type $octmode $data[1]"); |
683 | } else { |
683 | } else { |
684 | $this->log(3, "adding to transaction: $type " . implode(" ", $data)); |
684 | $this->log(3, "adding to transaction: $type " . implode(" ", $data)); |
685 | }
|
685 | }
|
686 | $this->file_operations[] = array($type, $data); |
686 | $this->file_operations[] = array($type, $data); |
687 | }
|
687 | }
|
688 | 688 | ||
689 | // }}}
|
689 | // }}}
|
690 | // {{{ startFileTransaction()
|
690 | // {{{ startFileTransaction()
|
691 | 691 | ||
692 | function startFileTransaction($rollback_in_case = false) |
692 | function startFileTransaction($rollback_in_case = false) |
693 | {
|
693 | {
|
694 | if (count($this->file_operations) && $rollback_in_case) { |
694 | if (count($this->file_operations) && $rollback_in_case) { |
695 | $this->rollbackFileTransaction(); |
695 | $this->rollbackFileTransaction(); |
696 | }
|
696 | }
|
697 | $this->file_operations = array(); |
697 | $this->file_operations = array(); |
698 | }
|
698 | }
|
699 | 699 | ||
700 | // }}}
|
700 | // }}}
|
701 | // {{{ commitFileTransaction()
|
701 | // {{{ commitFileTransaction()
|
702 | 702 | ||
703 | function commitFileTransaction() |
703 | function commitFileTransaction() |
704 | {
|
704 | {
|
705 | $n = count($this->file_operations); |
705 | $n = count($this->file_operations); |
706 | $this->log(2, "about to commit $n file operations"); |
706 | $this->log(2, "about to commit $n file operations"); |
707 | // {{{ first, check permissions and such manually
|
707 | // {{{ first, check permissions and such manually
|
708 | $errors = array(); |
708 | $errors = array(); |
709 | foreach ($this->file_operations as $tr) { |
709 | foreach ($this->file_operations as $tr) { |
710 | list($type, $data) = $tr; |
710 | list($type, $data) = $tr; |
711 | switch ($type) { |
711 | switch ($type) { |
712 | case 'rename': |
712 | case 'rename': |
713 | if (!file_exists($data[0])) { |
713 | if (!file_exists($data[0])) { |
714 | $errors[] = "cannot rename file $data[0], doesn't exist"; |
714 | $errors[] = "cannot rename file $data[0], doesn't exist"; |
715 | }
|
715 | }
|
716 | // check that dest dir. is writable
|
716 | // check that dest dir. is writable
|
717 | if (!is_writable(dirname($data[1]))) { |
717 | if (!is_writable(dirname($data[1]))) { |
718 | $errors[] = "permission denied ($type): $data[1]"; |
718 | $errors[] = "permission denied ($type): $data[1]"; |
719 | }
|
719 | }
|
720 | break; |
720 | break; |
721 | case 'chmod': |
721 | case 'chmod': |
722 | // check that file is writable
|
722 | // check that file is writable
|
723 | if (!is_writable($data[1])) { |
723 | if (!is_writable($data[1])) { |
724 | $errors[] = "permission denied ($type): $data[1] " . decoct($data[0]); |
724 | $errors[] = "permission denied ($type): $data[1] " . decoct($data[0]); |
725 | }
|
725 | }
|
726 | break; |
726 | break; |
727 | case 'delete': |
727 | case 'delete': |
728 | if (!file_exists($data[0])) { |
728 | if (!file_exists($data[0])) { |
729 | $this->log(2, "warning: file $data[0] doesn't exist, can't be deleted"); |
729 | $this->log(2, "warning: file $data[0] doesn't exist, can't be deleted"); |
730 | }
|
730 | }
|
731 | // check that directory is writable
|
731 | // check that directory is writable
|
732 | if (file_exists($data[0])) { |
732 | if (file_exists($data[0])) { |
733 | if (!is_writable(dirname($data[0]))) { |
733 | if (!is_writable(dirname($data[0]))) { |
734 | $errors[] = "permission denied ($type): $data[0]"; |
734 | $errors[] = "permission denied ($type): $data[0]"; |
735 | } else { |
735 | } else { |
736 | // make sure the file to be deleted can be opened for writing
|
736 | // make sure the file to be deleted can be opened for writing
|
737 | $fp = false; |
737 | $fp = false; |
738 | if (!is_dir($data[0]) && |
738 | if (!is_dir($data[0]) && |
739 | (!is_writable($data[0]) || !($fp = @fopen($data[0], 'a')))) { |
739 | (!is_writable($data[0]) || !($fp = @fopen($data[0], 'a')))) { |
740 | $errors[] = "permission denied ($type): $data[0]"; |
740 | $errors[] = "permission denied ($type): $data[0]"; |
741 | } elseif ($fp) { |
741 | } elseif ($fp) { |
742 | fclose($fp); |
742 | fclose($fp); |
743 | }
|
743 | }
|
744 | }
|
744 | }
|
745 | }
|
745 | }
|
746 | break; |
746 | break; |
747 | }
|
747 | }
|
748 | 748 | ||
749 | }
|
749 | }
|
750 | // }}}
|
750 | // }}}
|
751 | $m = sizeof($errors); |
751 | $m = sizeof($errors); |
752 | if ($m > 0) { |
752 | if ($m > 0) { |
753 | foreach ($errors as $error) { |
753 | foreach ($errors as $error) { |
754 | if (!isset($this->_options['soft'])) { |
754 | if (!isset($this->_options['soft'])) { |
755 | $this->log(1, $error); |
755 | $this->log(1, $error); |
756 | }
|
756 | }
|
757 | }
|
757 | }
|
758 | if (!isset($this->_options['ignore-errors'])) { |
758 | if (!isset($this->_options['ignore-errors'])) { |
759 | return false; |
759 | return false; |
760 | }
|
760 | }
|
761 | }
|
761 | }
|
762 | $this->_dirtree = array(); |
762 | $this->_dirtree = array(); |
763 | // {{{ really commit the transaction
|
763 | // {{{ really commit the transaction
|
764 | foreach ($this->file_operations as $i => $tr) { |
764 | foreach ($this->file_operations as $i => $tr) { |
765 | if (!$tr) { |
765 | if (!$tr) { |
766 | // support removal of non-existing backups
|
766 | // support removal of non-existing backups
|
767 | continue; |
767 | continue; |
768 | }
|
768 | }
|
769 | list($type, $data) = $tr; |
769 | list($type, $data) = $tr; |
770 | switch ($type) { |
770 | switch ($type) { |
771 | case 'backup': |
771 | case 'backup': |
772 | if (!file_exists($data[0])) { |
772 | if (!file_exists($data[0])) { |
773 | $this->file_operations[$i] = false; |
773 | $this->file_operations[$i] = false; |
774 | break; |
774 | break; |
775 | }
|
775 | }
|
776 | if (!@copy($data[0], $data[0] . '.bak')) { |
776 | if (!@copy($data[0], $data[0] . '.bak')) { |
777 | $this->log(1, 'Could not copy ' . $data[0] . ' to ' . $data[0] . |
777 | $this->log(1, 'Could not copy ' . $data[0] . ' to ' . $data[0] . |
778 | '.bak ' . $php_errormsg); |
778 | '.bak ' . $php_errormsg); |
779 | return false; |
779 | return false; |
780 | }
|
780 | }
|
781 | $this->log(3, "+ backup $data[0] to $data[0].bak"); |
781 | $this->log(3, "+ backup $data[0] to $data[0].bak"); |
782 | break; |
782 | break; |
783 | case 'removebackup': |
783 | case 'removebackup': |
784 | if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak')) { |
784 | if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak')) { |
785 | unlink($data[0] . '.bak'); |
785 | unlink($data[0] . '.bak'); |
786 | $this->log(3, "+ rm backup of $data[0] ($data[0].bak)"); |
786 | $this->log(3, "+ rm backup of $data[0] ($data[0].bak)"); |
787 | }
|
787 | }
|
788 | break; |
788 | break; |
789 | case 'rename': |
789 | case 'rename': |
790 | if (file_exists($data[1])) { |
790 | if (file_exists($data[1])) { |
791 | $test = @unlink($data[1]); |
791 | $test = @unlink($data[1]); |
792 | } else { |
792 | } else { |
793 | $test = null; |
793 | $test = null; |
794 | }
|
794 | }
|
795 | if (!$test && file_exists($data[1])) { |
795 | if (!$test && file_exists($data[1])) { |
796 | if ($data[2]) { |
796 | if ($data[2]) { |
797 | $extra = ', this extension must be installed manually. Rename to "' . |
797 | $extra = ', this extension must be installed manually. Rename to "' . |
798 | basename($data[1]) . '"'; |
798 | basename($data[1]) . '"'; |
799 | } else { |
799 | } else { |
800 | $extra = ''; |
800 | $extra = ''; |
801 | }
|
801 | }
|
802 | if (!isset($this->_options['soft'])) { |
802 | if (!isset($this->_options['soft'])) { |
803 | $this->log(1, 'Could not delete ' . $data[1] . ', cannot rename ' . |
803 | $this->log(1, 'Could not delete ' . $data[1] . ', cannot rename ' . |
804 | $data[0] . $extra); |
804 | $data[0] . $extra); |
805 | }
|
805 | }
|
806 | if (!isset($this->_options['ignore-errors'])) { |
806 | if (!isset($this->_options['ignore-errors'])) { |
807 | return false; |
807 | return false; |
808 | }
|
808 | }
|
809 | }
|
809 | }
|
810 | // permissions issues with rename - copy() is far superior
|
810 | // permissions issues with rename - copy() is far superior
|
811 | $perms = @fileperms($data[0]); |
811 | $perms = @fileperms($data[0]); |
812 | if (!@copy($data[0], $data[1])) { |
812 | if (!@copy($data[0], $data[1])) { |
813 | $this->log(1, 'Could not rename ' . $data[0] . ' to ' . $data[1] . |
813 | $this->log(1, 'Could not rename ' . $data[0] . ' to ' . $data[1] . |
814 | ' ' . $php_errormsg); |
814 | ' ' . $php_errormsg); |
815 | return false; |
815 | return false; |
816 | }
|
816 | }
|
817 | // copy over permissions, otherwise they are lost
|
817 | // copy over permissions, otherwise they are lost
|
818 | @chmod($data[1], $perms); |
818 | @chmod($data[1], $perms); |
819 | @unlink($data[0]); |
819 | @unlink($data[0]); |
820 | $this->log(3, "+ mv $data[0] $data[1]"); |
820 | $this->log(3, "+ mv $data[0] $data[1]"); |
821 | break; |
821 | break; |
822 | case 'chmod': |
822 | case 'chmod': |
823 | if (!@chmod($data[1], $data[0])) { |
823 | if (!@chmod($data[1], $data[0])) { |
824 | $this->log(1, 'Could not chmod ' . $data[1] . ' to ' . |
824 | $this->log(1, 'Could not chmod ' . $data[1] . ' to ' . |
825 | decoct($data[0]) . ' ' . $php_errormsg); |
825 | decoct($data[0]) . ' ' . $php_errormsg); |
826 | return false; |
826 | return false; |
827 | }
|
827 | }
|
828 | $octmode = decoct($data[0]); |
828 | $octmode = decoct($data[0]); |
829 | $this->log(3, "+ chmod $octmode $data[1]"); |
829 | $this->log(3, "+ chmod $octmode $data[1]"); |
830 | break; |
830 | break; |
831 | case 'delete': |
831 | case 'delete': |
832 | if (file_exists($data[0])) { |
832 | if (file_exists($data[0])) { |
833 | if (!@unlink($data[0])) { |
833 | if (!@unlink($data[0])) { |
834 | $this->log(1, 'Could not delete ' . $data[0] . ' ' . |
834 | $this->log(1, 'Could not delete ' . $data[0] . ' ' . |
835 | $php_errormsg); |
835 | $php_errormsg); |
836 | return false; |
836 | return false; |
837 | }
|
837 | }
|
838 | $this->log(3, "+ rm $data[0]"); |
838 | $this->log(3, "+ rm $data[0]"); |
839 | }
|
839 | }
|
840 | break; |
840 | break; |
841 | case 'rmdir': |
841 | case 'rmdir': |
842 | if (file_exists($data[0])) { |
842 | if (file_exists($data[0])) { |
843 | do { |
843 | do { |
844 | $testme = opendir($data[0]); |
844 | $testme = opendir($data[0]); |
845 | while (false !== ($entry = readdir($testme))) { |
845 | while (false !== ($entry = readdir($testme))) { |
846 | if ($entry == '.' || $entry == '..') { |
846 | if ($entry == '.' || $entry == '..') { |
847 | continue; |
847 | continue; |
848 | }
|
848 | }
|
849 | closedir($testme); |
849 | closedir($testme); |
850 | break 2; // this directory is not empty and can't be |
850 | break 2; // this directory is not empty and can't be |
851 | // deleted
|
851 | // deleted
|
852 | }
|
852 | }
|
853 | closedir($testme); |
853 | closedir($testme); |
854 | if (!@rmdir($data[0])) { |
854 | if (!@rmdir($data[0])) { |
855 | $this->log(1, 'Could not rmdir ' . $data[0] . ' ' . |
855 | $this->log(1, 'Could not rmdir ' . $data[0] . ' ' . |
856 | $php_errormsg); |
856 | $php_errormsg); |
857 | return false; |
857 | return false; |
858 | }
|
858 | }
|
859 | $this->log(3, "+ rmdir $data[0]"); |
859 | $this->log(3, "+ rmdir $data[0]"); |
860 | } while (false); |
860 | } while (false); |
861 | }
|
861 | }
|
862 | break; |
862 | break; |
863 | case 'installed_as': |
863 | case 'installed_as': |
864 | $this->pkginfo->setInstalledAs($data[0], $data[1]); |
864 | $this->pkginfo->setInstalledAs($data[0], $data[1]); |
865 | if (!isset($this->_dirtree[dirname($data[1])])) { |
865 | if (!isset($this->_dirtree[dirname($data[1])])) { |
866 | $this->_dirtree[dirname($data[1])] = true; |
866 | $this->_dirtree[dirname($data[1])] = true; |
867 | $this->pkginfo->setDirtree(dirname($data[1])); |
867 | $this->pkginfo->setDirtree(dirname($data[1])); |
868 | 868 | ||
869 | while(!empty($data[3]) && dirname($data[3]) != $data[3] && |
869 | while(!empty($data[3]) && dirname($data[3]) != $data[3] && |
870 | $data[3] != '/' && $data[3] != '\\') { |
870 | $data[3] != '/' && $data[3] != '\\') { |
871 | $this->pkginfo->setDirtree($pp = |
871 | $this->pkginfo->setDirtree($pp = |
872 | $this->_prependPath($data[3], $data[2])); |
872 | $this->_prependPath($data[3], $data[2])); |
873 | $this->_dirtree[$pp] = true; |
873 | $this->_dirtree[$pp] = true; |
874 | $data[3] = dirname($data[3]); |
874 | $data[3] = dirname($data[3]); |
875 | }
|
875 | }
|
876 | }
|
876 | }
|
877 | break; |
877 | break; |
878 | }
|
878 | }
|
879 | }
|
879 | }
|
880 | // }}}
|
880 | // }}}
|
881 | $this->log(2, "successfully committed $n file operations"); |
881 | $this->log(2, "successfully committed $n file operations"); |
882 | $this->file_operations = array(); |
882 | $this->file_operations = array(); |
883 | return true; |
883 | return true; |
884 | }
|
884 | }
|
885 | 885 | ||
886 | // }}}
|
886 | // }}}
|
887 | // {{{ rollbackFileTransaction()
|
887 | // {{{ rollbackFileTransaction()
|
888 | 888 | ||
889 | function rollbackFileTransaction() |
889 | function rollbackFileTransaction() |
890 | {
|
890 | {
|
891 | $n = count($this->file_operations); |
891 | $n = count($this->file_operations); |
892 | $this->log(2, "rolling back $n file operations"); |
892 | $this->log(2, "rolling back $n file operations"); |
893 | foreach ($this->file_operations as $tr) { |
893 | foreach ($this->file_operations as $tr) { |
894 | list($type, $data) = $tr; |
894 | list($type, $data) = $tr; |
895 | switch ($type) { |
895 | switch ($type) { |
896 | case 'backup': |
896 | case 'backup': |
897 | if (file_exists($data[0] . '.bak')) { |
897 | if (file_exists($data[0] . '.bak')) { |
898 | if (file_exists($data[0] && is_writable($data[0]))) { |
898 | if (file_exists($data[0] && is_writable($data[0]))) { |
899 | unlink($data[0]); |
899 | unlink($data[0]); |
900 | }
|
900 | }
|
901 | @copy($data[0] . '.bak', $data[0]); |
901 | @copy($data[0] . '.bak', $data[0]); |
902 | $this->log(3, "+ restore $data[0] from $data[0].bak"); |
902 | $this->log(3, "+ restore $data[0] from $data[0].bak"); |
903 | }
|
903 | }
|
904 | break; |
904 | break; |
905 | case 'removebackup': |
905 | case 'removebackup': |
906 | if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak')) { |
906 | if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak')) { |
907 | unlink($data[0] . '.bak'); |
907 | unlink($data[0] . '.bak'); |
908 | $this->log(3, "+ rm backup of $data[0] ($data[0].bak)"); |
908 | $this->log(3, "+ rm backup of $data[0] ($data[0].bak)"); |
909 | }
|
909 | }
|
910 | break; |
910 | break; |
911 | case 'rename': |
911 | case 'rename': |
912 | @unlink($data[0]); |
912 | @unlink($data[0]); |
913 | $this->log(3, "+ rm $data[0]"); |
913 | $this->log(3, "+ rm $data[0]"); |
914 | break; |
914 | break; |
915 | case 'mkdir': |
915 | case 'mkdir': |
916 | @rmdir($data[0]); |
916 | @rmdir($data[0]); |
917 | $this->log(3, "+ rmdir $data[0]"); |
917 | $this->log(3, "+ rmdir $data[0]"); |
918 | break; |
918 | break; |
919 | case 'chmod': |
919 | case 'chmod': |
920 | break; |
920 | break; |
921 | case 'delete': |
921 | case 'delete': |
922 | break; |
922 | break; |
923 | case 'installed_as': |
923 | case 'installed_as': |
924 | $this->pkginfo->setInstalledAs($data[0], false); |
924 | $this->pkginfo->setInstalledAs($data[0], false); |
925 | break; |
925 | break; |
926 | }
|
926 | }
|
927 | }
|
927 | }
|
928 | $this->pkginfo->resetDirtree(); |
928 | $this->pkginfo->resetDirtree(); |
929 | $this->file_operations = array(); |
929 | $this->file_operations = array(); |
930 | }
|
930 | }
|
931 | 931 | ||
932 | // }}}
|
932 | // }}}
|
933 | // {{{ mkDirHier($dir)
|
933 | // {{{ mkDirHier($dir)
|
934 | 934 | ||
935 | function mkDirHier($dir) |
935 | function mkDirHier($dir) |
936 | {
|
936 | {
|
937 | $this->addFileOperation('mkdir', array($dir)); |
937 | $this->addFileOperation('mkdir', array($dir)); |
938 | return parent::mkDirHier($dir); |
938 | return parent::mkDirHier($dir); |
939 | }
|
939 | }
|
940 | 940 | ||
941 | // }}}
|
941 | // }}}
|
942 | // {{{ download()
|
942 | // {{{ download()
|
943 | 943 | ||
944 | /**
|
944 | /**
|
945 | * Download any files and their dependencies, if necessary
|
945 | * Download any files and their dependencies, if necessary
|
946 | *
|
946 | *
|
947 | * @param array a mixed list of package names, local files, or package.xml
|
947 | * @param array a mixed list of package names, local files, or package.xml
|
948 | * @param PEAR_Config
|
948 | * @param PEAR_Config
|
949 | * @param array options from the command line
|
949 | * @param array options from the command line
|
950 | * @param array this is the array that will be populated with packages to
|
950 | * @param array this is the array that will be populated with packages to
|
951 | * install. Format of each entry:
|
951 | * install. Format of each entry:
|
952 | *
|
952 | *
|
953 | * <code>
|
953 | * <code>
|
954 | * array('pkg' => 'package_name', 'file' => '/path/to/local/file',
|
954 | * array('pkg' => 'package_name', 'file' => '/path/to/local/file',
|
955 | * 'info' => array() // parsed package.xml
|
955 | * 'info' => array() // parsed package.xml
|
956 | * );
|
956 | * );
|
957 | * </code>
|
957 | * </code>
|
958 | * @param array this will be populated with any error messages
|
958 | * @param array this will be populated with any error messages
|
959 | * @param false private recursion variable
|
959 | * @param false private recursion variable
|
960 | * @param false private recursion variable
|
960 | * @param false private recursion variable
|
961 | * @param false private recursion variable
|
961 | * @param false private recursion variable
|
962 | * @deprecated in favor of PEAR_Downloader
|
962 | * @deprecated in favor of PEAR_Downloader
|
963 | */
|
963 | */
|
964 | function download($packages, $options, &$config, &$installpackages, |
964 | function download($packages, $options, &$config, &$installpackages, |
965 | &$errors, $installed = false, $willinstall = false, $state = false) |
965 | &$errors, $installed = false, $willinstall = false, $state = false) |
966 | {
|
966 | {
|
967 | // trickiness: initialize here
|
967 | // trickiness: initialize here
|
968 | parent::PEAR_Downloader($this->ui, $options, $config); |
968 | parent::PEAR_Downloader($this->ui, $options, $config); |
969 | $ret = parent::download($packages); |
969 | $ret = parent::download($packages); |
970 | $errors = $this->getErrorMsgs(); |
970 | $errors = $this->getErrorMsgs(); |
971 | $installpackages = $this->getDownloadedPackages(); |
971 | $installpackages = $this->getDownloadedPackages(); |
972 | trigger_error("PEAR Warning: PEAR_Installer::download() is deprecated " . |
972 | trigger_error("PEAR Warning: PEAR_Installer::download() is deprecated " . |
973 | "in favor of PEAR_Downloader class", E_USER_WARNING); |
973 | "in favor of PEAR_Downloader class", E_USER_WARNING); |
974 | return $ret; |
974 | return $ret; |
975 | }
|
975 | }
|
976 | 976 | ||
977 | // }}}
|
977 | // }}}
|
978 | // {{{ _parsePackageXml()
|
978 | // {{{ _parsePackageXml()
|
979 | 979 | ||
980 | function _parsePackageXml(&$descfile, &$tmpdir) |
980 | function _parsePackageXml(&$descfile, &$tmpdir) |
981 | {
|
981 | {
|
982 | if (substr($descfile, -4) == '.xml') { |
982 | if (substr($descfile, -4) == '.xml') { |
983 | $tmpdir = false; |
983 | $tmpdir = false; |
984 | } else { |
984 | } else { |
985 | // {{{ Decompress pack in tmp dir -------------------------------------
|
985 | // {{{ Decompress pack in tmp dir -------------------------------------
|
986 | 986 | ||
987 | // To allow relative package file names
|
987 | // To allow relative package file names
|
988 | $descfile = realpath($descfile); |
988 | $descfile = realpath($descfile); |
989 | 989 | ||
990 | if (PEAR::isError($tmpdir = System::mktemp('-d'))) { |
990 | if (PEAR::isError($tmpdir = System::mktemp('-d'))) { |
991 | return $tmpdir; |
991 | return $tmpdir; |
992 | }
|
992 | }
|
993 | $this->log(3, '+ tmp dir created at ' . $tmpdir); |
993 | $this->log(3, '+ tmp dir created at ' . $tmpdir); |
994 | // }}}
|
994 | // }}}
|
995 | }
|
995 | }
|
996 | // Parse xml file -----------------------------------------------
|
996 | // Parse xml file -----------------------------------------------
|
997 | $pkg = new PEAR_PackageFile($this->config, $this->debug, $tmpdir); |
997 | $pkg = new PEAR_PackageFile($this->config, $this->debug, $tmpdir); |
998 | PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); |
998 | PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); |
999 | $p = &$pkg->fromAnyFile($descfile, PEAR_VALIDATE_INSTALLING); |
999 | $p = &$pkg->fromAnyFile($descfile, PEAR_VALIDATE_INSTALLING); |
1000 | PEAR::staticPopErrorHandling(); |
1000 | PEAR::staticPopErrorHandling(); |
1001 | if (PEAR::isError($p)) { |
1001 | if (PEAR::isError($p)) { |
1002 | if (is_array($p->getUserInfo())) { |
1002 | if (is_array($p->getUserInfo())) { |
1003 | foreach ($p->getUserInfo() as $err) { |
1003 | foreach ($p->getUserInfo() as $err) { |
1004 | $loglevel = $err['level'] == 'error' ? 0 : 1; |
1004 | $loglevel = $err['level'] == 'error' ? 0 : 1; |
1005 | if (!isset($this->_options['soft'])) { |
1005 | if (!isset($this->_options['soft'])) { |
1006 | $this->log($loglevel, ucfirst($err['level']) . ': ' . $err['message']); |
1006 | $this->log($loglevel, ucfirst($err['level']) . ': ' . $err['message']); |
1007 | }
|
1007 | }
|
1008 | }
|
1008 | }
|
1009 | }
|
1009 | }
|
1010 | return $this->raiseError('Installation failed: invalid package file'); |
1010 | return $this->raiseError('Installation failed: invalid package file'); |
1011 | } else { |
1011 | } else { |
1012 | $descfile = $p->getPackageFile(); |
1012 | $descfile = $p->getPackageFile(); |
1013 | }
|
1013 | }
|
1014 | return $p; |
1014 | return $p; |
1015 | }
|
1015 | }
|
1016 | 1016 | ||
1017 | // }}}
|
1017 | // }}}
|
1018 | /**
|
1018 | /**
|
1019 | * Set the list of PEAR_Downloader_Package objects to allow more sane
|
1019 | * Set the list of PEAR_Downloader_Package objects to allow more sane
|
1020 | * dependency validation
|
1020 | * dependency validation
|
1021 | * @param array
|
1021 | * @param array
|
1022 | */
|
1022 | */
|
1023 | function setDownloadedPackages(&$pkgs) |
1023 | function setDownloadedPackages(&$pkgs) |
1024 | {
|
1024 | {
|
1025 | PEAR::pushErrorHandling(PEAR_ERROR_RETURN); |
1025 | PEAR::pushErrorHandling(PEAR_ERROR_RETURN); |
1026 | $err = $this->analyzeDependencies($pkgs); |
1026 | $err = $this->analyzeDependencies($pkgs); |
1027 | PEAR::popErrorHandling(); |
1027 | PEAR::popErrorHandling(); |
1028 | if (PEAR::isError($err)) { |
1028 | if (PEAR::isError($err)) { |
1029 | return $err; |
1029 | return $err; |
1030 | }
|
1030 | }
|
1031 | $this->_downloadedPackages = &$pkgs; |
1031 | $this->_downloadedPackages = &$pkgs; |
1032 | }
|
1032 | }
|
1033 | 1033 | ||
1034 | /**
|
1034 | /**
|
1035 | * Set the list of PEAR_Downloader_Package objects to allow more sane
|
1035 | * Set the list of PEAR_Downloader_Package objects to allow more sane
|
1036 | * dependency validation
|
1036 | * dependency validation
|
1037 | * @param array
|
1037 | * @param array
|
1038 | */
|
1038 | */
|
1039 | function setUninstallPackages(&$pkgs) |
1039 | function setUninstallPackages(&$pkgs) |
1040 | {
|
1040 | {
|
1041 | $this->_downloadedPackages = &$pkgs; |
1041 | $this->_downloadedPackages = &$pkgs; |
1042 | }
|
1042 | }
|
1043 | 1043 | ||
1044 | function getInstallPackages() |
1044 | function getInstallPackages() |
1045 | {
|
1045 | {
|
1046 | return $this->_downloadedPackages; |
1046 | return $this->_downloadedPackages; |
1047 | }
|
1047 | }
|
1048 | 1048 | ||
1049 | // {{{ install()
|
1049 | // {{{ install()
|
1050 | 1050 | ||
1051 | /**
|
1051 | /**
|
1052 | * Installs the files within the package file specified.
|
1052 | * Installs the files within the package file specified.
|
1053 | *
|
1053 | *
|
1054 | * @param string|PEAR_Downloader_Package $pkgfile path to the package file,
|
1054 | * @param string|PEAR_Downloader_Package $pkgfile path to the package file,
|
1055 | * or a pre-initialized packagefile object
|
1055 | * or a pre-initialized packagefile object
|
1056 | * @param array $options
|
1056 | * @param array $options
|
1057 | * recognized options:
|
1057 | * recognized options:
|
1058 | * - installroot : optional prefix directory for installation
|
1058 | * - installroot : optional prefix directory for installation
|
1059 | * - force : force installation
|
1059 | * - force : force installation
|
1060 | * - register-only : update registry but don't install files
|
1060 | * - register-only : update registry but don't install files
|
1061 | * - upgrade : upgrade existing install
|
1061 | * - upgrade : upgrade existing install
|
1062 | * - soft : fail silently
|
1062 | * - soft : fail silently
|
1063 | * - nodeps : ignore dependency conflicts/missing dependencies
|
1063 | * - nodeps : ignore dependency conflicts/missing dependencies
|
1064 | * - alldeps : install all dependencies
|
1064 | * - alldeps : install all dependencies
|
1065 | * - onlyreqdeps : install only required dependencies
|
1065 | * - onlyreqdeps : install only required dependencies
|
1066 | *
|
1066 | *
|
1067 | * @return array|PEAR_Error package info if successful
|
1067 | * @return array|PEAR_Error package info if successful
|
1068 | */
|
1068 | */
|
1069 | 1069 | ||
1070 | function install($pkgfile, $options = array()) |
1070 | function install($pkgfile, $options = array()) |
1071 | {
|
1071 | {
|
1072 | $this->_options = $options; |
1072 | $this->_options = $options; |
1073 | $this->_registry = &$this->config->getRegistry(); |
1073 | $this->_registry = &$this->config->getRegistry(); |
1074 | if (is_object($pkgfile)) { |
1074 | if (is_object($pkgfile)) { |
1075 | $dlpkg = &$pkgfile; |
1075 | $dlpkg = &$pkgfile; |
1076 | $pkg = $pkgfile->getPackageFile(); |
1076 | $pkg = $pkgfile->getPackageFile(); |
1077 | $pkgfile = $pkg->getArchiveFile(); |
1077 | $pkgfile = $pkg->getArchiveFile(); |
1078 | $descfile = $pkg->getPackageFile(); |
1078 | $descfile = $pkg->getPackageFile(); |
1079 | $tmpdir = dirname($descfile); |
1079 | $tmpdir = dirname($descfile); |
1080 | } else { |
1080 | } else { |
1081 | $descfile = $pkgfile; |
1081 | $descfile = $pkgfile; |
1082 | $tmpdir = ''; |
1082 | $tmpdir = ''; |
1083 | if (PEAR::isError($pkg = &$this->_parsePackageXml($descfile, $tmpdir))) { |
1083 | if (PEAR::isError($pkg = &$this->_parsePackageXml($descfile, $tmpdir))) { |
1084 | return $pkg; |
1084 | return $pkg; |
1085 | }
|
1085 | }
|
1086 | }
|
1086 | }
|
1087 | 1087 | ||
1088 | if (realpath($descfile) != realpath($pkgfile)) { |
1088 | if (realpath($descfile) != realpath($pkgfile)) { |
1089 | $tar = new Archive_Tar($pkgfile); |
1089 | $tar = new Archive_Tar($pkgfile); |
1090 | if (!$tar->extract($tmpdir)) { |
1090 | if (!$tar->extract($tmpdir)) { |
1091 | return $this->raiseError("unable to unpack $pkgfile"); |
1091 | return $this->raiseError("unable to unpack $pkgfile"); |
1092 | }
|
1092 | }
|
1093 | }
|
1093 | }
|
1094 | 1094 | ||
1095 | $pkgname = $pkg->getName(); |
1095 | $pkgname = $pkg->getName(); |
1096 | $channel = $pkg->getChannel(); |
1096 | $channel = $pkg->getChannel(); |
1097 | if (isset($this->_options['packagingroot'])) { |
1097 | if (isset($this->_options['packagingroot'])) { |
1098 | $regdir = $this->_prependPath( |
1098 | $regdir = $this->_prependPath( |
1099 | $this->config->get('php_dir', null, 'pear.php.net'), |
1099 | $this->config->get('php_dir', null, 'pear.php.net'), |
1100 | $this->_options['packagingroot']); |
1100 | $this->_options['packagingroot']); |
1101 | $packrootphp_dir = $this->_prependPath( |
1101 | $packrootphp_dir = $this->_prependPath( |
1102 | $this->config->get('php_dir', null, $channel), |
1102 | $this->config->get('php_dir', null, $channel), |
1103 | $this->_options['packagingroot']); |
1103 | $this->_options['packagingroot']); |
1104 | }
|
1104 | }
|
1105 | 1105 | ||
1106 | if (isset($options['installroot'])) { |
1106 | if (isset($options['installroot'])) { |
1107 | $this->config->setInstallRoot($options['installroot']); |
1107 | $this->config->setInstallRoot($options['installroot']); |
1108 | $this->_registry = &$this->config->getRegistry(); |
1108 | $this->_registry = &$this->config->getRegistry(); |
1109 | $installregistry = &$this->_registry; |
1109 | $installregistry = &$this->_registry; |
1110 | $this->installroot = ''; // all done automagically now |
1110 | $this->installroot = ''; // all done automagically now |
1111 | $php_dir = $this->config->get('php_dir', null, $channel); |
1111 | $php_dir = $this->config->get('php_dir', null, $channel); |
1112 | } else { |
1112 | } else { |
1113 | $this->config->setInstallRoot(false); |
1113 | $this->config->setInstallRoot(false); |
1114 | $this->_registry = &$this->config->getRegistry(); |
1114 | $this->_registry = &$this->config->getRegistry(); |
1115 | if (isset($this->_options['packagingroot'])) { |
1115 | if (isset($this->_options['packagingroot'])) { |
1116 | $installregistry = &new PEAR_Registry($regdir); |
1116 | $installregistry = &new PEAR_Registry($regdir); |
1117 | if (!$installregistry->channelExists($channel, true)) { |
1117 | if (!$installregistry->channelExists($channel, true)) { |
1118 | // we need to fake a channel-discover of this channel
|
1118 | // we need to fake a channel-discover of this channel
|
1119 | $chanobj = $this->_registry->getChannel($channel, true); |
1119 | $chanobj = $this->_registry->getChannel($channel, true); |
1120 | $installregistry->addChannel($chanobj); |
1120 | $installregistry->addChannel($chanobj); |
1121 | }
|
1121 | }
|
1122 | $php_dir = $packrootphp_dir; |
1122 | $php_dir = $packrootphp_dir; |
1123 | } else { |
1123 | } else { |
1124 | $installregistry = &$this->_registry; |
1124 | $installregistry = &$this->_registry; |
1125 | $php_dir = $this->config->get('php_dir', null, $channel); |
1125 | $php_dir = $this->config->get('php_dir', null, $channel); |
1126 | }
|
1126 | }
|
1127 | $this->installroot = ''; |
1127 | $this->installroot = ''; |
1128 | }
|
1128 | }
|
1129 | 1129 | ||
1130 | // {{{ checks to do when not in "force" mode
|
1130 | // {{{ checks to do when not in "force" mode
|
1131 | if (empty($options['force']) && |
1131 | if (empty($options['force']) && |
1132 | (file_exists($this->config->get('php_dir')) && |
1132 | (file_exists($this->config->get('php_dir')) && |
1133 | is_dir($this->config->get('php_dir')))) { |
1133 | is_dir($this->config->get('php_dir')))) { |
1134 | $testp = $channel == 'pear.php.net' ? $pkgname : array($channel, $pkgname); |
1134 | $testp = $channel == 'pear.php.net' ? $pkgname : array($channel, $pkgname); |
1135 | $instfilelist = $pkg->getInstallationFileList(true); |
1135 | $instfilelist = $pkg->getInstallationFileList(true); |
1136 | if (PEAR::isError($instfilelist)) { |
1136 | if (PEAR::isError($instfilelist)) { |
1137 | return $instfilelist; |
1137 | return $instfilelist; |
1138 | }
|
1138 | }
|
1139 | // ensure we have the most accurate registry
|
1139 | // ensure we have the most accurate registry
|
1140 | $installregistry->flushFileMap(); |
1140 | $installregistry->flushFileMap(); |
1141 | $test = $installregistry->checkFileMap($instfilelist, $testp, '1.1'); |
1141 | $test = $installregistry->checkFileMap($instfilelist, $testp, '1.1'); |
1142 | if (PEAR::isError($test)) { |
1142 | if (PEAR::isError($test)) { |
1143 | return $test; |
1143 | return $test; |
1144 | }
|
1144 | }
|
1145 | if (sizeof($test)) { |
1145 | if (sizeof($test)) { |
1146 | $pkgs = $this->getInstallPackages(); |
1146 | $pkgs = $this->getInstallPackages(); |
1147 | $found = false; |
1147 | $found = false; |
1148 | foreach ($pkgs as $param) { |
1148 | foreach ($pkgs as $param) { |
1149 | if ($pkg->isSubpackageOf($param)) { |
1149 | if ($pkg->isSubpackageOf($param)) { |
1150 | $found = true; |
1150 | $found = true; |
1151 | break; |
1151 | break; |
1152 | }
|
1152 | }
|
1153 | }
|
1153 | }
|
1154 | if ($found) { |
1154 | if ($found) { |
1155 | // subpackages can conflict with earlier versions of parent packages
|
1155 | // subpackages can conflict with earlier versions of parent packages
|
1156 | $parentreg = $installregistry->packageInfo($param->getPackage(), null, $param->getChannel()); |
1156 | $parentreg = $installregistry->packageInfo($param->getPackage(), null, $param->getChannel()); |
1157 | $tmp = $test; |
1157 | $tmp = $test; |
1158 | foreach ($tmp as $file => $info) { |
1158 | foreach ($tmp as $file => $info) { |
1159 | if (is_array($info)) { |
1159 | if (is_array($info)) { |
1160 | if (strtolower($info[1]) == strtolower($param->getPackage()) && |
1160 | if (strtolower($info[1]) == strtolower($param->getPackage()) && |
1161 | strtolower($info[0]) == strtolower($param->getChannel())) { |
1161 | strtolower($info[0]) == strtolower($param->getChannel())) { |
1162 | unset($test[$file]); |
1162 | unset($test[$file]); |
1163 | unset($parentreg['filelist'][$file]); |
1163 | unset($parentreg['filelist'][$file]); |
1164 | }
|
1164 | }
|
1165 | } else { |
1165 | } else { |
1166 | if (strtolower($param->getChannel()) != 'pear.php.net') { |
1166 | if (strtolower($param->getChannel()) != 'pear.php.net') { |
1167 | continue; |
1167 | continue; |
1168 | }
|
1168 | }
|
1169 | if (strtolower($info) == strtolower($param->getPackage())) { |
1169 | if (strtolower($info) == strtolower($param->getPackage())) { |
1170 | unset($test[$file]); |
1170 | unset($test[$file]); |
1171 | unset($parentreg['filelist'][$file]); |
1171 | unset($parentreg['filelist'][$file]); |
1172 | }
|
1172 | }
|
1173 | }
|
1173 | }
|
1174 | }
|
1174 | }
|
1175 | $pfk = &new PEAR_PackageFile($this->config); |
1175 | $pfk = &new PEAR_PackageFile($this->config); |
1176 | $parentpkg = &$pfk->fromArray($parentreg); |
1176 | $parentpkg = &$pfk->fromArray($parentreg); |
1177 | $installregistry->updatePackage2($parentpkg); |
1177 | $installregistry->updatePackage2($parentpkg); |
1178 | }
|
1178 | }
|
1179 | if ($param->getChannel() == 'pecl.php.net' && isset($options['upgrade'])) { |
1179 | if ($param->getChannel() == 'pecl.php.net' && isset($options['upgrade'])) { |
1180 | $tmp = $test; |
1180 | $tmp = $test; |
1181 | foreach ($tmp as $file => $info) { |
1181 | foreach ($tmp as $file => $info) { |
1182 | if (is_string($info)) { |
1182 | if (is_string($info)) { |
1183 | // pear.php.net packages are always stored as strings
|
1183 | // pear.php.net packages are always stored as strings
|
1184 | if (strtolower($info) == strtolower($param->getPackage())) { |
1184 | if (strtolower($info) == strtolower($param->getPackage())) { |
1185 | // upgrading existing package
|
1185 | // upgrading existing package
|
1186 | unset($test[$file]); |
1186 | unset($test[$file]); |
1187 | }
|
1187 | }
|
1188 | }
|
1188 | }
|
1189 | }
|
1189 | }
|
1190 | }
|
1190 | }
|
1191 | if (sizeof($test)) { |
1191 | if (sizeof($test)) { |
1192 | $msg = "$channel/$pkgname: conflicting files found:\n"; |
1192 | $msg = "$channel/$pkgname: conflicting files found:\n"; |
1193 | $longest = max(array_map("strlen", array_keys($test))); |
1193 | $longest = max(array_map("strlen", array_keys($test))); |
1194 | $fmt = "%${longest}s (%s)\n"; |
1194 | $fmt = "%${longest}s (%s)\n"; |
1195 | foreach ($test as $file => $info) { |
1195 | foreach ($test as $file => $info) { |
1196 | if (!is_array($info)) { |
1196 | if (!is_array($info)) { |
1197 | $info = array('pear.php.net', $info); |
1197 | $info = array('pear.php.net', $info); |
1198 | }
|
1198 | }
|
1199 | $info = $info[0] . '/' . $info[1]; |
1199 | $info = $info[0] . '/' . $info[1]; |
1200 | $msg .= sprintf($fmt, $file, $info); |
1200 | $msg .= sprintf($fmt, $file, $info); |
1201 | }
|
1201 | }
|
1202 | if (!isset($options['ignore-errors'])) { |
1202 | if (!isset($options['ignore-errors'])) { |
1203 | return $this->raiseError($msg); |
1203 | return $this->raiseError($msg); |
1204 | } else { |
1204 | } else { |
1205 | if (!isset($options['soft'])) { |
1205 | if (!isset($options['soft'])) { |
1206 | $this->log(0, "WARNING: $msg"); |
1206 | $this->log(0, "WARNING: $msg"); |
1207 | }
|
1207 | }
|
1208 | }
|
1208 | }
|
1209 | }
|
1209 | }
|
1210 | }
|
1210 | }
|
1211 | }
|
1211 | }
|
1212 | // }}}
|
1212 | // }}}
|
1213 | 1213 | ||
1214 | $this->startFileTransaction(); |
1214 | $this->startFileTransaction(); |
1215 | 1215 | ||
1216 | if (empty($options['upgrade']) && empty($options['soft'])) { |
1216 | if (empty($options['upgrade']) && empty($options['soft'])) { |
1217 | // checks to do only when installing new packages
|
1217 | // checks to do only when installing new packages
|
1218 | if ($channel == 'pecl.php.net') { |
1218 | if ($channel == 'pecl.php.net') { |
1219 | $test = $installregistry->packageExists($pkgname, $channel); |
1219 | $test = $installregistry->packageExists($pkgname, $channel); |
1220 | if (!$test) { |
1220 | if (!$test) { |
1221 | $test = $installregistry->packageExists($pkgname, 'pear.php.net'); |
1221 | $test = $installregistry->packageExists($pkgname, 'pear.php.net'); |
1222 | }
|
1222 | }
|
1223 | } else { |
1223 | } else { |
1224 | $test = $installregistry->packageExists($pkgname, $channel); |
1224 | $test = $installregistry->packageExists($pkgname, $channel); |
1225 | }
|
1225 | }
|
1226 | if (empty($options['force']) && $test) { |
1226 | if (empty($options['force']) && $test) { |
1227 | return $this->raiseError("$channel/$pkgname is already installed"); |
1227 | return $this->raiseError("$channel/$pkgname is already installed"); |
1228 | }
|
1228 | }
|
1229 | } else { |
1229 | } else { |
1230 | $usechannel = $channel; |
1230 | $usechannel = $channel; |
1231 | if ($channel == 'pecl.php.net') { |
1231 | if ($channel == 'pecl.php.net') { |
1232 | $test = $installregistry->packageExists($pkgname, $channel); |
1232 | $test = $installregistry->packageExists($pkgname, $channel); |
1233 | if (!$test) { |
1233 | if (!$test) { |
1234 | $test = $installregistry->packageExists($pkgname, 'pear.php.net'); |
1234 | $test = $installregistry->packageExists($pkgname, 'pear.php.net'); |
1235 | $usechannel = 'pear.php.net'; |
1235 | $usechannel = 'pear.php.net'; |
1236 | }
|
1236 | }
|
1237 | } else { |
1237 | } else { |
1238 | $test = $installregistry->packageExists($pkgname, $channel); |
1238 | $test = $installregistry->packageExists($pkgname, $channel); |
1239 | }
|
1239 | }
|
1240 | if ($test) { |
1240 | if ($test) { |
1241 | $v1 = $installregistry->packageInfo($pkgname, 'version', $usechannel); |
1241 | $v1 = $installregistry->packageInfo($pkgname, 'version', $usechannel); |
1242 | $v2 = $pkg->getVersion(); |
1242 | $v2 = $pkg->getVersion(); |
1243 | $cmp = version_compare("$v1", "$v2", 'gt'); |
1243 | $cmp = version_compare("$v1", "$v2", 'gt'); |
1244 | if (empty($options['force']) && !version_compare("$v2", "$v1", 'gt')) { |
1244 | if (empty($options['force']) && !version_compare("$v2", "$v1", 'gt')) { |
1245 | return $this->raiseError("upgrade to a newer version ($v2 is not newer than $v1)"); |
1245 | return $this->raiseError("upgrade to a newer version ($v2 is not newer than $v1)"); |
1246 | }
|
1246 | }
|
1247 | if (empty($options['register-only'])) { |
1247 | if (empty($options['register-only'])) { |
1248 | // when upgrading, remove old release's files first:
|
1248 | // when upgrading, remove old release's files first:
|
1249 | if (PEAR::isError($err = $this->_deletePackageFiles($pkgname, $usechannel, |
1249 | if (PEAR::isError($err = $this->_deletePackageFiles($pkgname, $usechannel, |
1250 | true))) { |
1250 | true))) { |
1251 | if (!isset($options['ignore-errors'])) { |
1251 | if (!isset($options['ignore-errors'])) { |
1252 | return $this->raiseError($err); |
1252 | return $this->raiseError($err); |
1253 | } else { |
1253 | } else { |
1254 | if (!isset($options['soft'])) { |
1254 | if (!isset($options['soft'])) { |
1255 | $this->log(0, 'WARNING: ' . $err->getMessage()); |
1255 | $this->log(0, 'WARNING: ' . $err->getMessage()); |
1256 | }
|
1256 | }
|
1257 | }
|
1257 | }
|
1258 | } else { |
1258 | } else { |
1259 | $backedup = $err; |
1259 | $backedup = $err; |
1260 | }
|
1260 | }
|
1261 | }
|
1261 | }
|
1262 | }
|
1262 | }
|
1263 | }
|
1263 | }
|
1264 | 1264 | ||
1265 | // {{{ Copy files to dest dir ---------------------------------------
|
1265 | // {{{ Copy files to dest dir ---------------------------------------
|
1266 | 1266 | ||
1267 | // info from the package it self we want to access from _installFile
|
1267 | // info from the package it self we want to access from _installFile
|
1268 | $this->pkginfo = &$pkg; |
1268 | $this->pkginfo = &$pkg; |
1269 | // used to determine whether we should build any C code
|
1269 | // used to determine whether we should build any C code
|
1270 | $this->source_files = 0; |
1270 | $this->source_files = 0; |
1271 | 1271 | ||
1272 | $savechannel = $this->config->get('default_channel'); |
1272 | $savechannel = $this->config->get('default_channel'); |
1273 | if (empty($options['register-only']) && !is_dir($php_dir)) { |
1273 | if (empty($options['register-only']) && !is_dir($php_dir)) { |
1274 | if (PEAR::isError(System::mkdir(array('-p'), $php_dir))) { |
1274 | if (PEAR::isError(System::mkdir(array('-p'), $php_dir))) { |
1275 | return $this->raiseError("no installation destination directory '$php_dir'\n"); |
1275 | return $this->raiseError("no installation destination directory '$php_dir'\n"); |
1276 | }
|
1276 | }
|
1277 | }
|
1277 | }
|
1278 | 1278 | ||
1279 | $tmp_path = dirname($descfile); |
1279 | $tmp_path = dirname($descfile); |
1280 | if (substr($pkgfile, -4) != '.xml') { |
1280 | if (substr($pkgfile, -4) != '.xml') { |
1281 | $tmp_path .= DIRECTORY_SEPARATOR . $pkgname . '-' . $pkg->getVersion(); |
1281 | $tmp_path .= DIRECTORY_SEPARATOR . $pkgname . '-' . $pkg->getVersion(); |
1282 | }
|
1282 | }
|
1283 | 1283 | ||
1284 | $this->configSet('default_channel', $channel); |
1284 | $this->configSet('default_channel', $channel); |
1285 | // {{{ install files
|
1285 | // {{{ install files
|
1286 | 1286 | ||
1287 | $ver = $pkg->getPackagexmlVersion(); |
1287 | $ver = $pkg->getPackagexmlVersion(); |
1288 | if (version_compare($ver, '2.0', '>=')) { |
1288 | if (version_compare($ver, '2.0', '>=')) { |
1289 | $filelist = $pkg->getInstallationFilelist(); |
1289 | $filelist = $pkg->getInstallationFilelist(); |
1290 | } else { |
1290 | } else { |
1291 | $filelist = $pkg->getFileList(); |
1291 | $filelist = $pkg->getFileList(); |
1292 | }
|
1292 | }
|
1293 | if (PEAR::isError($filelist)) { |
1293 | if (PEAR::isError($filelist)) { |
1294 | return $filelist; |
1294 | return $filelist; |
1295 | }
|
1295 | }
|
1296 | $p = &$installregistry->getPackage($pkgname, $channel); |
1296 | $p = &$installregistry->getPackage($pkgname, $channel); |
1297 | if (empty($options['register-only']) && $p) { |
1297 | if (empty($options['register-only']) && $p) { |
1298 | $dirtree = $p->getDirTree(); |
1298 | $dirtree = $p->getDirTree(); |
1299 | } else { |
1299 | } else { |
1300 | $dirtree = false; |
1300 | $dirtree = false; |
1301 | }
|
1301 | }
|
1302 | $pkg->resetFilelist(); |
1302 | $pkg->resetFilelist(); |
1303 | $pkg->setLastInstalledVersion($installregistry->packageInfo($pkg->getPackage(), |
1303 | $pkg->setLastInstalledVersion($installregistry->packageInfo($pkg->getPackage(), |
1304 | 'version', $pkg->getChannel())); |
1304 | 'version', $pkg->getChannel())); |
1305 | foreach ($filelist as $file => $atts) { |
1305 | foreach ($filelist as $file => $atts) { |
1306 | if ($pkg->getPackagexmlVersion() == '1.0') { |
1306 | if ($pkg->getPackagexmlVersion() == '1.0') { |
1307 | $this->expectError(PEAR_INSTALLER_FAILED); |
1307 | $this->expectError(PEAR_INSTALLER_FAILED); |
1308 | $res = $this->_installFile($file, $atts, $tmp_path, $options); |
1308 | $res = $this->_installFile($file, $atts, $tmp_path, $options); |
1309 | $this->popExpect(); |
1309 | $this->popExpect(); |
1310 | } else { |
1310 | } else { |
1311 | $this->expectError(PEAR_INSTALLER_FAILED); |
1311 | $this->expectError(PEAR_INSTALLER_FAILED); |
1312 | $res = $this->_installFile2($pkg, $file, $atts, $tmp_path, $options); |
1312 | $res = $this->_installFile2($pkg, $file, $atts, $tmp_path, $options); |
1313 | $this->popExpect(); |
1313 | $this->popExpect(); |
1314 | }
|
1314 | }
|
1315 | if (PEAR::isError($res)) { |
1315 | if (PEAR::isError($res)) { |
1316 | if (empty($options['ignore-errors'])) { |
1316 | if (empty($options['ignore-errors'])) { |
1317 | $this->rollbackFileTransaction(); |
1317 | $this->rollbackFileTransaction(); |
1318 | if ($res->getMessage() == "file does not exist") { |
1318 | if ($res->getMessage() == "file does not exist") { |
1319 | $this->raiseError("file $file in package.xml does not exist"); |
1319 | $this->raiseError("file $file in package.xml does not exist"); |
1320 | }
|
1320 | }
|
1321 | return $this->raiseError($res); |
1321 | return $this->raiseError($res); |
1322 | } else { |
1322 | } else { |
1323 | if (!isset($options['soft'])) { |
1323 | if (!isset($options['soft'])) { |
1324 | $this->log(0, "Warning: " . $res->getMessage()); |
1324 | $this->log(0, "Warning: " . $res->getMessage()); |
1325 | }
|
1325 | }
|
1326 | }
|
1326 | }
|
1327 | }
|
1327 | }
|
1328 | $real = isset($atts['attribs']) ? $atts['attribs'] : $atts; |
1328 | $real = isset($atts['attribs']) ? $atts['attribs'] : $atts; |
1329 | if ($res == PEAR_INSTALLER_OK && $real['role'] != 'src') { |
1329 | if ($res == PEAR_INSTALLER_OK && $real['role'] != 'src') { |
1330 | // Register files that were installed
|
1330 | // Register files that were installed
|
1331 | $pkg->installedFile($file, $atts); |
1331 | $pkg->installedFile($file, $atts); |
1332 | }
|
1332 | }
|
1333 | }
|
1333 | }
|
1334 | // }}}
|
1334 | // }}}
|
1335 | 1335 | ||
1336 | // {{{ compile and install source files
|
1336 | // {{{ compile and install source files
|
1337 | if ($this->source_files > 0 && empty($options['nobuild'])) { |
1337 | if ($this->source_files > 0 && empty($options['nobuild'])) { |
1338 | if (PEAR::isError($err = |
1338 | if (PEAR::isError($err = |
1339 | $this->_compileSourceFiles($savechannel, $pkg))) { |
1339 | $this->_compileSourceFiles($savechannel, $pkg))) { |
1340 | return $err; |
1340 | return $err; |
1341 | }
|
1341 | }
|
1342 | }
|
1342 | }
|
1343 | // }}}
|
1343 | // }}}
|
1344 | 1344 | ||
1345 | if (isset($backedup)) { |
1345 | if (isset($backedup)) { |
1346 | $this->_removeBackups($backedup); |
1346 | $this->_removeBackups($backedup); |
1347 | }
|
1347 | }
|
1348 | if (!$this->commitFileTransaction()) { |
1348 | if (!$this->commitFileTransaction()) { |
1349 | $this->rollbackFileTransaction(); |
1349 | $this->rollbackFileTransaction(); |
1350 | $this->configSet('default_channel', $savechannel); |
1350 | $this->configSet('default_channel', $savechannel); |
1351 | return $this->raiseError("commit failed", PEAR_INSTALLER_FAILED); |
1351 | return $this->raiseError("commit failed", PEAR_INSTALLER_FAILED); |
1352 | }
|
1352 | }
|
1353 | // }}}
|
1353 | // }}}
|
1354 | 1354 | ||
1355 | $ret = false; |
1355 | $ret = false; |
1356 | $installphase = 'install'; |
1356 | $installphase = 'install'; |
1357 | $oldversion = false; |
1357 | $oldversion = false; |
1358 | // {{{ Register that the package is installed -----------------------
|
1358 | // {{{ Register that the package is installed -----------------------
|
1359 | if (empty($options['upgrade'])) { |
1359 | if (empty($options['upgrade'])) { |
1360 | // if 'force' is used, replace the info in registry
|
1360 | // if 'force' is used, replace the info in registry
|
1361 | $usechannel = $channel; |
1361 | $usechannel = $channel; |
1362 | if ($channel == 'pecl.php.net') { |
1362 | if ($channel == 'pecl.php.net') { |
1363 | $test = $installregistry->packageExists($pkgname, $channel); |
1363 | $test = $installregistry->packageExists($pkgname, $channel); |
1364 | if (!$test) { |
1364 | if (!$test) { |
1365 | $test = $installregistry->packageExists($pkgname, 'pear.php.net'); |
1365 | $test = $installregistry->packageExists($pkgname, 'pear.php.net'); |
1366 | $usechannel = 'pear.php.net'; |
1366 | $usechannel = 'pear.php.net'; |
1367 | }
|
1367 | }
|
1368 | } else { |
1368 | } else { |
1369 | $test = $installregistry->packageExists($pkgname, $channel); |
1369 | $test = $installregistry->packageExists($pkgname, $channel); |
1370 | }
|
1370 | }
|
1371 | if (!empty($options['force']) && $test) { |
1371 | if (!empty($options['force']) && $test) { |
1372 | $oldversion = $installregistry->packageInfo($pkgname, 'version', $usechannel); |
1372 | $oldversion = $installregistry->packageInfo($pkgname, 'version', $usechannel); |
1373 | $installregistry->deletePackage($pkgname, $usechannel); |
1373 | $installregistry->deletePackage($pkgname, $usechannel); |
1374 | }
|
1374 | }
|
1375 | $ret = $installregistry->addPackage2($pkg); |
1375 | $ret = $installregistry->addPackage2($pkg); |
1376 | } else { |
1376 | } else { |
1377 | if ($dirtree) { |
1377 | if ($dirtree) { |
1378 | $this->startFileTransaction(); |
1378 | $this->startFileTransaction(); |
1379 | // attempt to delete empty directories
|
1379 | // attempt to delete empty directories
|
1380 | uksort($dirtree, array($this, '_sortDirs')); |
1380 | uksort($dirtree, array($this, '_sortDirs')); |
1381 | foreach($dirtree as $dir => $notused) { |
1381 | foreach($dirtree as $dir => $notused) { |
1382 | $this->addFileOperation('rmdir', array($dir)); |
1382 | $this->addFileOperation('rmdir', array($dir)); |
1383 | }
|
1383 | }
|
1384 | $this->commitFileTransaction(); |
1384 | $this->commitFileTransaction(); |
1385 | }
|
1385 | }
|
1386 | $usechannel = $channel; |
1386 | $usechannel = $channel; |
1387 | if ($channel == 'pecl.php.net') { |
1387 | if ($channel == 'pecl.php.net') { |
1388 | $test = $installregistry->packageExists($pkgname, $channel); |
1388 | $test = $installregistry->packageExists($pkgname, $channel); |
1389 | if (!$test) { |
1389 | if (!$test) { |
1390 | $test = $installregistry->packageExists($pkgname, 'pear.php.net'); |
1390 | $test = $installregistry->packageExists($pkgname, 'pear.php.net'); |
1391 | $usechannel = 'pear.php.net'; |
1391 | $usechannel = 'pear.php.net'; |
1392 | }
|
1392 | }
|
1393 | } else { |
1393 | } else { |
1394 | $test = $installregistry->packageExists($pkgname, $channel); |
1394 | $test = $installregistry->packageExists($pkgname, $channel); |
1395 | }
|
1395 | }
|
1396 | // new: upgrade installs a package if it isn't installed
|
1396 | // new: upgrade installs a package if it isn't installed
|
1397 | if (!$test) { |
1397 | if (!$test) { |
1398 | $ret = $installregistry->addPackage2($pkg); |
1398 | $ret = $installregistry->addPackage2($pkg); |
1399 | } else { |
1399 | } else { |
1400 | if ($usechannel != $channel) { |
1400 | if ($usechannel != $channel) { |
1401 | $installregistry->deletePackage($pkgname, $usechannel); |
1401 | $installregistry->deletePackage($pkgname, $usechannel); |
1402 | $ret = $installregistry->addPackage2($pkg); |
1402 | $ret = $installregistry->addPackage2($pkg); |
1403 | } else { |
1403 | } else { |
1404 | $ret = $installregistry->updatePackage2($pkg); |
1404 | $ret = $installregistry->updatePackage2($pkg); |
1405 | }
|
1405 | }
|
1406 | $installphase = 'upgrade'; |
1406 | $installphase = 'upgrade'; |
1407 | }
|
1407 | }
|
1408 | }
|
1408 | }
|
1409 | if (!$ret) { |
1409 | if (!$ret) { |
1410 | $this->configSet('default_channel', $savechannel); |
1410 | $this->configSet('default_channel', $savechannel); |
1411 | return $this->raiseError("Adding package $channel/$pkgname to registry failed"); |
1411 | return $this->raiseError("Adding package $channel/$pkgname to registry failed"); |
1412 | }
|
1412 | }
|
1413 | // }}}
|
1413 | // }}}
|
1414 | $this->configSet('default_channel', $savechannel); |
1414 | $this->configSet('default_channel', $savechannel); |
1415 | if (class_exists('PEAR_Task_Common')) { // this is auto-included if any tasks exist |
1415 | if (class_exists('PEAR_Task_Common')) { // this is auto-included if any tasks exist |
1416 | if (PEAR_Task_Common::hasPostinstallTasks()) { |
1416 | if (PEAR_Task_Common::hasPostinstallTasks()) { |
1417 | PEAR_Task_Common::runPostinstallTasks($installphase); |
1417 | PEAR_Task_Common::runPostinstallTasks($installphase); |
1418 | }
|
1418 | }
|
1419 | }
|
1419 | }
|
1420 | return $pkg->toArray(true); |
1420 | return $pkg->toArray(true); |
1421 | }
|
1421 | }
|
1422 | 1422 | ||
1423 | // }}}
|
1423 | // }}}
|
1424 | 1424 | ||
1425 | // {{{ _compileSourceFiles()
|
1425 | // {{{ _compileSourceFiles()
|
1426 | /**
|
1426 | /**
|
1427 | * @param string
|
1427 | * @param string
|
1428 | * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
|
1428 | * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
|
1429 | */
|
1429 | */
|
1430 | function _compileSourceFiles($savechannel, &$filelist) |
1430 | function _compileSourceFiles($savechannel, &$filelist) |
1431 | {
|
1431 | {
|
1432 | require_once 'PEAR/Builder.php'; |
1432 | require_once 'PEAR/Builder.php'; |
1433 | $this->log(1, "$this->source_files source files, building"); |
1433 | $this->log(1, "$this->source_files source files, building"); |
1434 | $bob = &new PEAR_Builder($this->ui); |
1434 | $bob = &new PEAR_Builder($this->ui); |
1435 | $bob->debug = $this->debug; |
1435 | $bob->debug = $this->debug; |
1436 | $built = $bob->build($filelist, array(&$this, '_buildCallback')); |
1436 | $built = $bob->build($filelist, array(&$this, '_buildCallback')); |
1437 | if (PEAR::isError($built)) { |
1437 | if (PEAR::isError($built)) { |
1438 | $this->rollbackFileTransaction(); |
1438 | $this->rollbackFileTransaction(); |
1439 | $this->configSet('default_channel', $savechannel); |
1439 | $this->configSet('default_channel', $savechannel); |
1440 | return $built; |
1440 | return $built; |
1441 | }
|
1441 | }
|
1442 | $this->log(1, "\nBuild process completed successfully"); |
1442 | $this->log(1, "\nBuild process completed successfully"); |
1443 | foreach ($built as $ext) { |
1443 | foreach ($built as $ext) { |
1444 | $bn = basename($ext['file']); |
1444 | $bn = basename($ext['file']); |
1445 | list($_ext_name, $_ext_suff) = explode('.', $bn); |
1445 | list($_ext_name, $_ext_suff) = explode('.', $bn); |
1446 | if ($_ext_suff == '.so' || $_ext_suff == '.dll') { |
1446 | if ($_ext_suff == '.so' || $_ext_suff == '.dll') { |
1447 | if (extension_loaded($_ext_name)) { |
1447 | if (extension_loaded($_ext_name)) { |
1448 | $this->raiseError("Extension '$_ext_name' already loaded. " . |
1448 | $this->raiseError("Extension '$_ext_name' already loaded. " . |
1449 | 'Please unload it in your php.ini file ' . |
1449 | 'Please unload it in your php.ini file ' . |
1450 | 'prior to install or upgrade'); |
1450 | 'prior to install or upgrade'); |
1451 | }
|
1451 | }
|
1452 | $role = 'ext'; |
1452 | $role = 'ext'; |
1453 | } else { |
1453 | } else { |
1454 | $role = 'src'; |
1454 | $role = 'src'; |
1455 | }
|
1455 | }
|
1456 | $dest = $ext['dest']; |
1456 | $dest = $ext['dest']; |
1457 | $packagingroot = ''; |
1457 | $packagingroot = ''; |
1458 | if (isset($this->_options['packagingroot'])) { |
1458 | if (isset($this->_options['packagingroot'])) { |
1459 | $packagingroot = $this->_options['packagingroot']; |
1459 | $packagingroot = $this->_options['packagingroot']; |
1460 | }
|
1460 | }
|
1461 | $copyto = $this->_prependPath($dest, $packagingroot); |
1461 | $copyto = $this->_prependPath($dest, $packagingroot); |
1462 | if ($copyto != $dest) { |
1462 | if ($copyto != $dest) { |
1463 | $this->log(1, "Installing '$dest' as '$copyto'"); |
1463 | $this->log(1, "Installing '$dest' as '$copyto'"); |
1464 | } else { |
1464 | } else { |
1465 | $this->log(1, "Installing '$dest'"); |
1465 | $this->log(1, "Installing '$dest'"); |
1466 | }
|
1466 | }
|
1467 | $copydir = dirname($copyto); |
1467 | $copydir = dirname($copyto); |
1468 | // pretty much nothing happens if we are only registering the install
|
1468 | // pretty much nothing happens if we are only registering the install
|
1469 | if (empty($this->_options['register-only'])) { |
1469 | if (empty($this->_options['register-only'])) { |
1470 | if (!file_exists($copydir) || !is_dir($copydir)) { |
1470 | if (!file_exists($copydir) || !is_dir($copydir)) { |
1471 | if (!$this->mkDirHier($copydir)) { |
1471 | if (!$this->mkDirHier($copydir)) { |
1472 | return $this->raiseError("failed to mkdir $copydir", |
1472 | return $this->raiseError("failed to mkdir $copydir", |
1473 | PEAR_INSTALLER_FAILED); |
1473 | PEAR_INSTALLER_FAILED); |
1474 | }
|
1474 | }
|
1475 | $this->log(3, "+ mkdir $copydir"); |
1475 | $this->log(3, "+ mkdir $copydir"); |
1476 | }
|
1476 | }
|
1477 | if (!@copy($ext['file'], $copyto)) { |
1477 | if (!@copy($ext['file'], $copyto)) { |
1478 | return $this->raiseError("failed to write $copyto ($php_errormsg)", PEAR_INSTALLER_FAILED); |
1478 | return $this->raiseError("failed to write $copyto ($php_errormsg)", PEAR_INSTALLER_FAILED); |
1479 | }
|
1479 | }
|
1480 | $this->log(3, "+ cp $ext[file] $copyto"); |
1480 | $this->log(3, "+ cp $ext[file] $copyto"); |
1481 | $this->addFileOperation('rename', array($ext['file'], $copyto)); |
1481 | $this->addFileOperation('rename', array($ext['file'], $copyto)); |
1482 | if (!OS_WINDOWS) { |
1482 | if (!OS_WINDOWS) { |
1483 | $mode = 0666 & ~(int)octdec($this->config->get('umask')); |
1483 | $mode = 0666 & ~(int)octdec($this->config->get('umask')); |
1484 | $this->addFileOperation('chmod', array($mode, $copyto)); |
1484 | $this->addFileOperation('chmod', array($mode, $copyto)); |
1485 | if (!@chmod($copyto, $mode)) { |
1485 | if (!@chmod($copyto, $mode)) { |
1486 | $this->log(0, "failed to change mode of $copyto ($php_errormsg)"); |
1486 | $this->log(0, "failed to change mode of $copyto ($php_errormsg)"); |
1487 | }
|
1487 | }
|
1488 | }
|
1488 | }
|
1489 | }
|
1489 | }
|
1490 | 1490 | ||
1491 | if ($filelist->getPackageXmlVersion() == '1.0') { |
1491 | if ($filelist->getPackageXmlVersion() == '1.0') { |
1492 | $filelist->installedFile($bn, array( |
1492 | $filelist->installedFile($bn, array( |
1493 | 'role' => $role, |
1493 | 'role' => $role, |
1494 | 'name' => $bn, |
1494 | 'name' => $bn, |
1495 | 'installed_as' => $dest, |
1495 | 'installed_as' => $dest, |
1496 | 'php_api' => $ext['php_api'], |
1496 | 'php_api' => $ext['php_api'], |
1497 | 'zend_mod_api' => $ext['zend_mod_api'], |
1497 | 'zend_mod_api' => $ext['zend_mod_api'], |
1498 | 'zend_ext_api' => $ext['zend_ext_api'], |
1498 | 'zend_ext_api' => $ext['zend_ext_api'], |
1499 | )); |
1499 | )); |
1500 | } else { |
1500 | } else { |
1501 | $filelist->installedFile($bn, array('attribs' => array( |
1501 | $filelist->installedFile($bn, array('attribs' => array( |
1502 | 'role' => $role, |
1502 | 'role' => $role, |
1503 | 'name' => $bn, |
1503 | 'name' => $bn, |
1504 | 'installed_as' => $dest, |
1504 | 'installed_as' => $dest, |
1505 | 'php_api' => $ext['php_api'], |
1505 | 'php_api' => $ext['php_api'], |
1506 | 'zend_mod_api' => $ext['zend_mod_api'], |
1506 | 'zend_mod_api' => $ext['zend_mod_api'], |
1507 | 'zend_ext_api' => $ext['zend_ext_api'], |
1507 | 'zend_ext_api' => $ext['zend_ext_api'], |
1508 | ))); |
1508 | ))); |
1509 | }
|
1509 | }
|
1510 | }
|
1510 | }
|
1511 | }
|
1511 | }
|
1512 | 1512 | ||
1513 | // }}}
|
1513 | // }}}
|
1514 | function &getUninstallPackages() |
1514 | function &getUninstallPackages() |
1515 | {
|
1515 | {
|
1516 | return $this->_downloadedPackages; |
1516 | return $this->_downloadedPackages; |
1517 | }
|
1517 | }
|
1518 | // {{{ uninstall()
|
1518 | // {{{ uninstall()
|
1519 | 1519 | ||
1520 | /**
|
1520 | /**
|
1521 | * Uninstall a package
|
1521 | * Uninstall a package
|
1522 | *
|
1522 | *
|
1523 | * This method removes all files installed by the application, and then
|
1523 | * This method removes all files installed by the application, and then
|
1524 | * removes any empty directories.
|
1524 | * removes any empty directories.
|
1525 | * @param string package name
|
1525 | * @param string package name
|
1526 | * @param array Command-line options. Possibilities include:
|
1526 | * @param array Command-line options. Possibilities include:
|
1527 | *
|
1527 | *
|
1528 | * - installroot: base installation dir, if not the default
|
1528 | * - installroot: base installation dir, if not the default
|
1529 | * - register-only : update registry but don't remove files
|
1529 | * - register-only : update registry but don't remove files
|
1530 | * - nodeps: do not process dependencies of other packages to ensure
|
1530 | * - nodeps: do not process dependencies of other packages to ensure
|
1531 | * uninstallation does not break things
|
1531 | * uninstallation does not break things
|
1532 | */
|
1532 | */
|
1533 | function uninstall($package, $options = array()) |
1533 | function uninstall($package, $options = array()) |
1534 | {
|
1534 | {
|
1535 | if (isset($options['installroot'])) { |
1535 | if (isset($options['installroot'])) { |
1536 | $this->config->setInstallRoot($options['installroot']); |
1536 | $this->config->setInstallRoot($options['installroot']); |
1537 | $this->installroot = ''; |
1537 | $this->installroot = ''; |
1538 | } else { |
1538 | } else { |
1539 | $this->config->setInstallRoot(''); |
1539 | $this->config->setInstallRoot(''); |
1540 | $this->installroot = ''; |
1540 | $this->installroot = ''; |
1541 | }
|
1541 | }
|
1542 | $this->_registry = &$this->config->getRegistry(); |
1542 | $this->_registry = &$this->config->getRegistry(); |
1543 | if (is_object($package)) { |
1543 | if (is_object($package)) { |
1544 | $channel = $package->getChannel(); |
1544 | $channel = $package->getChannel(); |
1545 | $pkg = $package; |
1545 | $pkg = $package; |
1546 | $package = $pkg->getPackage(); |
1546 | $package = $pkg->getPackage(); |
1547 | } else { |
1547 | } else { |
1548 | $pkg = false; |
1548 | $pkg = false; |
1549 | $info = $this->_registry->parsePackageName($package, |
1549 | $info = $this->_registry->parsePackageName($package, |
1550 | $this->config->get('default_channel')); |
1550 | $this->config->get('default_channel')); |
1551 | $channel = $info['channel']; |
1551 | $channel = $info['channel']; |
1552 | $package = $info['package']; |
1552 | $package = $info['package']; |
1553 | }
|
1553 | }
|
1554 | $savechannel = $this->config->get('default_channel'); |
1554 | $savechannel = $this->config->get('default_channel'); |
1555 | $this->configSet('default_channel', $channel); |
1555 | $this->configSet('default_channel', $channel); |
1556 | if (!is_object($pkg)) { |
1556 | if (!is_object($pkg)) { |
1557 | $pkg = $this->_registry->getPackage($package, $channel); |
1557 | $pkg = $this->_registry->getPackage($package, $channel); |
1558 | }
|
1558 | }
|
1559 | if (!$pkg) { |
1559 | if (!$pkg) { |
1560 | $this->configSet('default_channel', $savechannel); |
1560 | $this->configSet('default_channel', $savechannel); |
1561 | return $this->raiseError($this->_registry->parsedPackageNameToString( |
1561 | return $this->raiseError($this->_registry->parsedPackageNameToString( |
1562 | array( |
1562 | array( |
1563 | 'channel' => $channel, |
1563 | 'channel' => $channel, |
1564 | 'package' => $package |
1564 | 'package' => $package |
1565 | ), true) . ' not installed'); |
1565 | ), true) . ' not installed'); |
1566 | }
|
1566 | }
|
1567 | if ($pkg->getInstalledBinary()) { |
1567 | if ($pkg->getInstalledBinary()) { |
1568 | // this is just an alias for a binary package
|
1568 | // this is just an alias for a binary package
|
1569 | return $this->_registry->deletePackage($package, $channel); |
1569 | return $this->_registry->deletePackage($package, $channel); |
1570 | }
|
1570 | }
|
1571 | $filelist = $pkg->getFilelist(); |
1571 | $filelist = $pkg->getFilelist(); |
1572 | PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); |
1572 | PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); |
1573 | if (!class_exists('PEAR_Dependency2')) { |
1573 | if (!class_exists('PEAR_Dependency2')) { |
1574 | require_once 'PEAR/Dependency2.php'; |
1574 | require_once 'PEAR/Dependency2.php'; |
1575 | }
|
1575 | }
|
1576 | $depchecker = &new PEAR_Dependency2($this->config, $options, |
1576 | $depchecker = &new PEAR_Dependency2($this->config, $options, |
1577 | array('channel' => $channel, 'package' => $package), |
1577 | array('channel' => $channel, 'package' => $package), |
1578 | PEAR_VALIDATE_UNINSTALLING); |
1578 | PEAR_VALIDATE_UNINSTALLING); |
1579 | $e = $depchecker->validatePackageUninstall($this); |
1579 | $e = $depchecker->validatePackageUninstall($this); |
1580 | PEAR::staticPopErrorHandling(); |
1580 | PEAR::staticPopErrorHandling(); |
1581 | if (PEAR::isError($e)) { |
1581 | if (PEAR::isError($e)) { |
1582 | if (!isset($options['ignore-errors'])) { |
1582 | if (!isset($options['ignore-errors'])) { |
1583 | return $this->raiseError($e); |
1583 | return $this->raiseError($e); |
1584 | } else { |
1584 | } else { |
1585 | if (!isset($options['soft'])) { |
1585 | if (!isset($options['soft'])) { |
1586 | $this->log(0, 'WARNING: ' . $e->getMessage()); |
1586 | $this->log(0, 'WARNING: ' . $e->getMessage()); |
1587 | }
|
1587 | }
|
1588 | }
|
1588 | }
|
1589 | } elseif (is_array($e)) { |
1589 | } elseif (is_array($e)) { |
1590 | if (!isset($options['soft'])) { |
1590 | if (!isset($options['soft'])) { |
1591 | $this->log(0, $e[0]); |
1591 | $this->log(0, $e[0]); |
1592 | }
|
1592 | }
|
1593 | }
|
1593 | }
|
1594 | $this->pkginfo = &$pkg; |
1594 | $this->pkginfo = &$pkg; |
1595 | // pretty much nothing happens if we are only registering the uninstall
|
1595 | // pretty much nothing happens if we are only registering the uninstall
|
1596 | if (empty($options['register-only'])) { |
1596 | if (empty($options['register-only'])) { |
1597 | // {{{ Delete the files
|
1597 | // {{{ Delete the files
|
1598 | $this->startFileTransaction(); |
1598 | $this->startFileTransaction(); |
1599 | PEAR::pushErrorHandling(PEAR_ERROR_RETURN); |
1599 | PEAR::pushErrorHandling(PEAR_ERROR_RETURN); |
1600 | if (PEAR::isError($err = $this->_deletePackageFiles($package, $channel))) { |
1600 | if (PEAR::isError($err = $this->_deletePackageFiles($package, $channel))) { |
1601 | PEAR::popErrorHandling(); |
1601 | PEAR::popErrorHandling(); |
1602 | $this->rollbackFileTransaction(); |
1602 | $this->rollbackFileTransaction(); |
1603 | $this->configSet('default_channel', $savechannel); |
1603 | $this->configSet('default_channel', $savechannel); |
1604 | if (!isset($options['ignore-errors'])) { |
1604 | if (!isset($options['ignore-errors'])) { |
1605 | return $this->raiseError($err); |
1605 | return $this->raiseError($err); |
1606 | } else { |
1606 | } else { |
1607 | if (!isset($options['soft'])) { |
1607 | if (!isset($options['soft'])) { |
1608 | $this->log(0, 'WARNING: ' . $err->getMessage()); |
1608 | $this->log(0, 'WARNING: ' . $err->getMessage()); |
1609 | }
|
1609 | }
|
1610 | }
|
1610 | }
|
1611 | } else { |
1611 | } else { |
1612 | PEAR::popErrorHandling(); |
1612 | PEAR::popErrorHandling(); |
1613 | }
|
1613 | }
|
1614 | if (!$this->commitFileTransaction()) { |
1614 | if (!$this->commitFileTransaction()) { |
1615 | $this->rollbackFileTransaction(); |
1615 | $this->rollbackFileTransaction(); |
1616 | if (!isset($options['ignore-errors'])) { |
1616 | if (!isset($options['ignore-errors'])) { |
1617 | return $this->raiseError("uninstall failed"); |
1617 | return $this->raiseError("uninstall failed"); |
1618 | } elseif (!isset($options['soft'])) { |
1618 | } elseif (!isset($options['soft'])) { |
1619 | $this->log(0, 'WARNING: uninstall failed'); |
1619 | $this->log(0, 'WARNING: uninstall failed'); |
1620 | }
|
1620 | }
|
1621 | } else { |
1621 | } else { |
1622 | $this->startFileTransaction(); |
1622 | $this->startFileTransaction(); |
1623 | if ($dirtree = $pkg->getDirTree()) { |
1623 | if ($dirtree = $pkg->getDirTree()) { |
1624 | // attempt to delete empty directories
|
1624 | // attempt to delete empty directories
|
1625 | uksort($dirtree, array($this, '_sortDirs')); |
1625 | uksort($dirtree, array($this, '_sortDirs')); |
1626 | foreach($dirtree as $dir => $notused) { |
1626 | foreach($dirtree as $dir => $notused) { |
1627 | $this->addFileOperation('rmdir', array($dir)); |
1627 | $this->addFileOperation('rmdir', array($dir)); |
1628 | }
|
1628 | }
|
1629 | } else { |
1629 | } else { |
1630 | $this->configSet('default_channel', $savechannel); |
1630 | $this->configSet('default_channel', $savechannel); |
1631 | return $this->_registry->deletePackage($package, $channel); |
1631 | return $this->_registry->deletePackage($package, $channel); |
1632 | }
|
1632 | }
|
1633 | if (!$this->commitFileTransaction()) { |
1633 | if (!$this->commitFileTransaction()) { |
1634 | $this->rollbackFileTransaction(); |
1634 | $this->rollbackFileTransaction(); |
1635 | if (!isset($options['ignore-errors'])) { |
1635 | if (!isset($options['ignore-errors'])) { |
1636 | return $this->raiseError("uninstall failed"); |
1636 | return $this->raiseError("uninstall failed"); |
1637 | } elseif (!isset($options['soft'])) { |
1637 | } elseif (!isset($options['soft'])) { |
1638 | $this->log(0, 'WARNING: uninstall failed'); |
1638 | $this->log(0, 'WARNING: uninstall failed'); |
1639 | }
|
1639 | }
|
1640 | }
|
1640 | }
|
1641 | }
|
1641 | }
|
1642 | // }}}
|
1642 | // }}}
|
1643 | }
|
1643 | }
|
1644 | 1644 | ||
1645 | $this->configSet('default_channel', $savechannel); |
1645 | $this->configSet('default_channel', $savechannel); |
1646 | // Register that the package is no longer installed
|
1646 | // Register that the package is no longer installed
|
1647 | return $this->_registry->deletePackage($package, $channel); |
1647 | return $this->_registry->deletePackage($package, $channel); |
1648 | }
|
1648 | }
|
1649 | 1649 | ||
1650 | /**
|
1650 | /**
|
1651 | * Sort a list of arrays of array(downloaded packagefilename) by dependency.
|
1651 | * Sort a list of arrays of array(downloaded packagefilename) by dependency.
|
1652 | *
|
1652 | *
|
1653 | * It also removes duplicate dependencies
|
1653 | * It also removes duplicate dependencies
|
1654 | * @param array an array of PEAR_PackageFile_v[1/2] objects
|
1654 | * @param array an array of PEAR_PackageFile_v[1/2] objects
|
1655 | * @return array|PEAR_Error array of array(packagefilename, package.xml contents)
|
1655 | * @return array|PEAR_Error array of array(packagefilename, package.xml contents)
|
1656 | */
|
1656 | */
|
1657 | function sortPackagesForUninstall(&$packages) |
1657 | function sortPackagesForUninstall(&$packages) |
1658 | {
|
1658 | {
|
1659 | $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->config); |
1659 | $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->config); |
1660 | if (PEAR::isError($this->_dependencyDB)) { |
1660 | if (PEAR::isError($this->_dependencyDB)) { |
1661 | return $this->_dependencyDB; |
1661 | return $this->_dependencyDB; |
1662 | }
|
1662 | }
|
1663 | usort($packages, array(&$this, '_sortUninstall')); |
1663 | usort($packages, array(&$this, '_sortUninstall')); |
1664 | }
|
1664 | }
|
1665 | 1665 | ||
1666 | function _sortUninstall($a, $b) |
1666 | function _sortUninstall($a, $b) |
1667 | {
|
1667 | {
|
1668 | if (!$a->getDeps() && !$b->getDeps()) { |
1668 | if (!$a->getDeps() && !$b->getDeps()) { |
1669 | return 0; // neither package has dependencies, order is insignificant |
1669 | return 0; // neither package has dependencies, order is insignificant |
1670 | }
|
1670 | }
|
1671 | if ($a->getDeps() && !$b->getDeps()) { |
1671 | if ($a->getDeps() && !$b->getDeps()) { |
1672 | return -1; // $a must be installed after $b because $a has dependencies |
1672 | return -1; // $a must be installed after $b because $a has dependencies |
1673 | }
|
1673 | }
|
1674 | if (!$a->getDeps() && $b->getDeps()) { |
1674 | if (!$a->getDeps() && $b->getDeps()) { |
1675 | return 1; // $b must be installed after $a because $b has dependencies |
1675 | return 1; // $b must be installed after $a because $b has dependencies |
1676 | }
|
1676 | }
|
1677 | // both packages have dependencies
|
1677 | // both packages have dependencies
|
1678 | if ($this->_dependencyDB->dependsOn($a, $b)) { |
1678 | if ($this->_dependencyDB->dependsOn($a, $b)) { |
1679 | return -1; |
1679 | return -1; |
1680 | }
|
1680 | }
|
1681 | if ($this->_dependencyDB->dependsOn($b, $a)) { |
1681 | if ($this->_dependencyDB->dependsOn($b, $a)) { |
1682 | return 1; |
1682 | return 1; |
1683 | }
|
1683 | }
|
1684 | return 0; |
1684 | return 0; |
1685 | }
|
1685 | }
|
1686 | 1686 | ||
1687 | // }}}
|
1687 | // }}}
|
1688 | // {{{ _sortDirs()
|
1688 | // {{{ _sortDirs()
|
1689 | function _sortDirs($a, $b) |
1689 | function _sortDirs($a, $b) |
1690 | {
|
1690 | {
|
1691 | if (strnatcmp($a, $b) == -1) return 1; |
1691 | if (strnatcmp($a, $b) == -1) return 1; |
1692 | if (strnatcmp($a, $b) == 1) return -1; |
1692 | if (strnatcmp($a, $b) == 1) return -1; |
1693 | return 0; |
1693 | return 0; |
1694 | }
|
1694 | }
|
1695 | 1695 | ||
1696 | // }}}
|
1696 | // }}}
|
1697 | 1697 | ||
1698 | // {{{ _buildCallback()
|
1698 | // {{{ _buildCallback()
|
1699 | 1699 | ||
1700 | function _buildCallback($what, $data) |
1700 | function _buildCallback($what, $data) |
1701 | {
|
1701 | {
|
1702 | if (($what == 'cmdoutput' && $this->debug > 1) || |
1702 | if (($what == 'cmdoutput' && $this->debug > 1) || |
1703 | ($what == 'output' && $this->debug > 0)) { |
1703 | ($what == 'output' && $this->debug > 0)) { |
1704 | $this->ui->outputData(rtrim($data), 'build'); |
1704 | $this->ui->outputData(rtrim($data), 'build'); |
1705 | }
|
1705 | }
|
1706 | }
|
1706 | }
|
1707 | 1707 | ||
1708 | // }}}
|
1708 | // }}}
|
1709 | }
|
1709 | }
|
1710 | 1710 | ||
1711 | // {{{ md5_file() utility function
|
1711 | // {{{ md5_file() utility function
|
1712 | if (!function_exists("md5_file")) { |
1712 | if (!function_exists("md5_file")) { |
1713 | function md5_file($filename) { |
1713 | function md5_file($filename) { |
1714 | if (!$fd = @fopen($file, 'r')) { |
1714 | if (!$fd = @fopen($file, 'r')) { |
1715 | return false; |
1715 | return false; |
1716 | }
|
1716 | }
|
1717 | fclose($fd); |
1717 | fclose($fd); |
1718 | return md5(file_get_contents($filename)); |
1718 | return md5(file_get_contents($filename)); |
1719 | }
|
1719 | }
|
1720 | }
|
1720 | }
|
1721 | // }}}
|
1721 | // }}}
|
1722 | 1722 | ||
1723 | ?>
|
1723 | ?>
|