Subversion Repositories Applications.gtt

Rev

Rev 94 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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