Install.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 5 |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2004 The PHP Group |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 3.0 of the PHP license, |
  9. // | that is bundled with this package in the file LICENSE, and is |
  10. // | available through the world-wide-web at the following url: |
  11. // | http://www.php.net/license/3_0.txt. |
  12. // | If you did not receive a copy of the PHP license and are unable to |
  13. // | obtain it through the world-wide-web, please send a note to |
  14. // | [email protected] so we can mail you a copy immediately. |
  15. // +----------------------------------------------------------------------+
  16. // | Author: Stig Sæther Bakken <[email protected]> |
  17. // +----------------------------------------------------------------------+
  18. //
  19. // $Id: Install.php,v 1.53.2.1 2004/10/19 04:08:42 cellog Exp $
  20. require_once "PEAR/Command/Common.php";
  21. require_once "PEAR/Installer.php";
  22. /**
  23. * PEAR commands for installation or deinstallation/upgrading of
  24. * packages.
  25. *
  26. */
  27. class PEAR_Command_Install extends PEAR_Command_Common
  28. {
  29. // {{{ properties
  30. var $commands = array(
  31. 'install' => array(
  32. 'summary' => 'Install Package',
  33. 'function' => 'doInstall',
  34. 'shortcut' => 'i',
  35. 'options' => array(
  36. 'force' => array(
  37. 'shortopt' => 'f',
  38. 'doc' => 'will overwrite newer installed packages',
  39. ),
  40. 'nodeps' => array(
  41. 'shortopt' => 'n',
  42. 'doc' => 'ignore dependencies, install anyway',
  43. ),
  44. 'register-only' => array(
  45. 'shortopt' => 'r',
  46. 'doc' => 'do not install files, only register the package as installed',
  47. ),
  48. 'soft' => array(
  49. 'shortopt' => 's',
  50. 'doc' => 'soft install, fail silently, or upgrade if already installed',
  51. ),
  52. 'nobuild' => array(
  53. 'shortopt' => 'B',
  54. 'doc' => 'don\'t build C extensions',
  55. ),
  56. 'nocompress' => array(
  57. 'shortopt' => 'Z',
  58. 'doc' => 'request uncompressed files when downloading',
  59. ),
  60. 'installroot' => array(
  61. 'shortopt' => 'R',
  62. 'arg' => 'DIR',
  63. 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
  64. ),
  65. 'ignore-errors' => array(
  66. 'doc' => 'force install even if there were errors',
  67. ),
  68. 'alldeps' => array(
  69. 'shortopt' => 'a',
  70. 'doc' => 'install all required and optional dependencies',
  71. ),
  72. 'onlyreqdeps' => array(
  73. 'shortopt' => 'o',
  74. 'doc' => 'install all required dependencies',
  75. ),
  76. ),
  77. 'doc' => '<package> ...
  78. Installs one or more PEAR packages. You can specify a package to
  79. install in four ways:
  80. "Package-1.0.tgz" : installs from a local file
  81. "http://example.com/Package-1.0.tgz" : installs from
  82. anywhere on the net.
  83. "package.xml" : installs the package described in
  84. package.xml. Useful for testing, or for wrapping a PEAR package in
  85. another package manager such as RPM.
  86. "Package" : queries your configured server
  87. ({config master_server}) and downloads the newest package with
  88. the preferred quality/state ({config preferred_state}).
  89. More than one package may be specified at once. It is ok to mix these
  90. four ways of specifying packages.
  91. '),
  92. 'upgrade' => array(
  93. 'summary' => 'Upgrade Package',
  94. 'function' => 'doInstall',
  95. 'shortcut' => 'up',
  96. 'options' => array(
  97. 'force' => array(
  98. 'shortopt' => 'f',
  99. 'doc' => 'overwrite newer installed packages',
  100. ),
  101. 'nodeps' => array(
  102. 'shortopt' => 'n',
  103. 'doc' => 'ignore dependencies, upgrade anyway',
  104. ),
  105. 'register-only' => array(
  106. 'shortopt' => 'r',
  107. 'doc' => 'do not install files, only register the package as upgraded',
  108. ),
  109. 'nobuild' => array(
  110. 'shortopt' => 'B',
  111. 'doc' => 'don\'t build C extensions',
  112. ),
  113. 'nocompress' => array(
  114. 'shortopt' => 'Z',
  115. 'doc' => 'request uncompressed files when downloading',
  116. ),
  117. 'installroot' => array(
  118. 'shortopt' => 'R',
  119. 'arg' => 'DIR',
  120. 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
  121. ),
  122. 'ignore-errors' => array(
  123. 'doc' => 'force install even if there were errors',
  124. ),
  125. 'alldeps' => array(
  126. 'shortopt' => 'a',
  127. 'doc' => 'install all required and optional dependencies',
  128. ),
  129. 'onlyreqdeps' => array(
  130. 'shortopt' => 'o',
  131. 'doc' => 'install all required dependencies',
  132. ),
  133. ),
  134. 'doc' => '<package> ...
  135. Upgrades one or more PEAR packages. See documentation for the
  136. "install" command for ways to specify a package.
  137. When upgrading, your package will be updated if the provided new
  138. package has a higher version number (use the -f option if you need to
  139. upgrade anyway).
  140. More than one package may be specified at once.
  141. '),
  142. 'upgrade-all' => array(
  143. 'summary' => 'Upgrade All Packages',
  144. 'function' => 'doInstall',
  145. 'shortcut' => 'ua',
  146. 'options' => array(
  147. 'nodeps' => array(
  148. 'shortopt' => 'n',
  149. 'doc' => 'ignore dependencies, upgrade anyway',
  150. ),
  151. 'register-only' => array(
  152. 'shortopt' => 'r',
  153. 'doc' => 'do not install files, only register the package as upgraded',
  154. ),
  155. 'nobuild' => array(
  156. 'shortopt' => 'B',
  157. 'doc' => 'don\'t build C extensions',
  158. ),
  159. 'nocompress' => array(
  160. 'shortopt' => 'Z',
  161. 'doc' => 'request uncompressed files when downloading',
  162. ),
  163. 'installroot' => array(
  164. 'shortopt' => 'R',
  165. 'arg' => 'DIR',
  166. 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
  167. ),
  168. 'ignore-errors' => array(
  169. 'doc' => 'force install even if there were errors',
  170. ),
  171. ),
  172. 'doc' => '
  173. Upgrades all packages that have a newer release available. Upgrades are
  174. done only if there is a release available of the state specified in
  175. "preferred_state" (currently {config preferred_state}), or a state considered
  176. more stable.
  177. '),
  178. 'uninstall' => array(
  179. 'summary' => 'Un-install Package',
  180. 'function' => 'doUninstall',
  181. 'shortcut' => 'un',
  182. 'options' => array(
  183. 'nodeps' => array(
  184. 'shortopt' => 'n',
  185. 'doc' => 'ignore dependencies, uninstall anyway',
  186. ),
  187. 'register-only' => array(
  188. 'shortopt' => 'r',
  189. 'doc' => 'do not remove files, only register the packages as not installed',
  190. ),
  191. 'installroot' => array(
  192. 'shortopt' => 'R',
  193. 'arg' => 'DIR',
  194. 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
  195. ),
  196. 'ignore-errors' => array(
  197. 'doc' => 'force install even if there were errors',
  198. ),
  199. ),
  200. 'doc' => '<package> ...
  201. Uninstalls one or more PEAR packages. More than one package may be
  202. specified at once.
  203. '),
  204. 'bundle' => array(
  205. 'summary' => 'Unpacks a Pecl Package',
  206. 'function' => 'doBundle',
  207. 'shortcut' => 'bun',
  208. 'options' => array(
  209. 'destination' => array(
  210. 'shortopt' => 'd',
  211. 'arg' => 'DIR',
  212. 'doc' => 'Optional destination directory for unpacking (defaults to current path or "ext" if exists)',
  213. ),
  214. 'force' => array(
  215. 'shortopt' => 'f',
  216. 'doc' => 'Force the unpacking even if there were errors in the package',
  217. ),
  218. ),
  219. 'doc' => '<package>
  220. Unpacks a Pecl Package into the selected location. It will download the
  221. package if needed.
  222. '),
  223. );
  224. // }}}
  225. // {{{ constructor
  226. /**
  227. * PEAR_Command_Install constructor.
  228. *
  229. * @access public
  230. */
  231. function PEAR_Command_Install(&$ui, &$config)
  232. {
  233. parent::PEAR_Command_Common($ui, $config);
  234. }
  235. // }}}
  236. // {{{ doInstall()
  237. function doInstall($command, $options, $params)
  238. {
  239. require_once 'PEAR/Downloader.php';
  240. if (empty($this->installer)) {
  241. $this->installer = &new PEAR_Installer($this->ui);
  242. }
  243. if ($command == 'upgrade') {
  244. $options['upgrade'] = true;
  245. }
  246. if ($command == 'upgrade-all') {
  247. include_once "PEAR/Remote.php";
  248. $options['upgrade'] = true;
  249. $remote = &new PEAR_Remote($this->config);
  250. $state = $this->config->get('preferred_state');
  251. if (empty($state) || $state == 'any') {
  252. $latest = $remote->call("package.listLatestReleases");
  253. } else {
  254. $latest = $remote->call("package.listLatestReleases", $state);
  255. }
  256. if (PEAR::isError($latest)) {
  257. return $latest;
  258. }
  259. $reg = new PEAR_Registry($this->config->get('php_dir'));
  260. $installed = array_flip($reg->listPackages());
  261. $params = array();
  262. foreach ($latest as $package => $info) {
  263. $package = strtolower($package);
  264. if (!isset($installed[$package])) {
  265. // skip packages we don't have installed
  266. continue;
  267. }
  268. $inst_version = $reg->packageInfo($package, 'version');
  269. if (version_compare("$info[version]", "$inst_version", "le")) {
  270. // installed version is up-to-date
  271. continue;
  272. }
  273. $params[] = $package;
  274. $this->ui->outputData(array('data' => "Will upgrade $package"), $command);
  275. }
  276. }
  277. $this->downloader = &new PEAR_Downloader($this->ui, $options, $this->config);
  278. $errors = array();
  279. $downloaded = array();
  280. $this->downloader->download($params);
  281. $errors = $this->downloader->getErrorMsgs();
  282. if (count($errors)) {
  283. $err['data'] = array($errors);
  284. $err['headline'] = 'Install Errors';
  285. $this->ui->outputData($err);
  286. return $this->raiseError("$command failed");
  287. }
  288. $downloaded = $this->downloader->getDownloadedPackages();
  289. $this->installer->sortPkgDeps($downloaded);
  290. foreach ($downloaded as $pkg) {
  291. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  292. $info = $this->installer->install($pkg['file'], $options, $this->config);
  293. PEAR::popErrorHandling();
  294. if (PEAR::isError($info)) {
  295. $this->ui->outputData('ERROR: ' .$info->getMessage());
  296. continue;
  297. }
  298. if (is_array($info)) {
  299. if ($this->config->get('verbose') > 0) {
  300. $label = "$info[package] $info[version]";
  301. $out = array('data' => "$command ok: $label");
  302. if (isset($info['release_warnings'])) {
  303. $out['release_warnings'] = $info['release_warnings'];
  304. }
  305. $this->ui->outputData($out, $command);
  306. }
  307. } else {
  308. return $this->raiseError("$command failed");
  309. }
  310. }
  311. return true;
  312. }
  313. // }}}
  314. // {{{ doUninstall()
  315. function doUninstall($command, $options, $params)
  316. {
  317. if (empty($this->installer)) {
  318. $this->installer = &new PEAR_Installer($this->ui);
  319. }
  320. if (sizeof($params) < 1) {
  321. return $this->raiseError("Please supply the package(s) you want to uninstall");
  322. }
  323. include_once 'PEAR/Registry.php';
  324. $reg = new PEAR_Registry($this->config->get('php_dir'));
  325. $newparams = array();
  326. $badparams = array();
  327. foreach ($params as $pkg) {
  328. $info = $reg->packageInfo($pkg);
  329. if ($info === null) {
  330. $badparams[] = $pkg;
  331. } else {
  332. $newparams[] = $info;
  333. }
  334. }
  335. $this->installer->sortPkgDeps($newparams, true);
  336. $params = array();
  337. foreach($newparams as $info) {
  338. $params[] = $info['info']['package'];
  339. }
  340. $params = array_merge($params, $badparams);
  341. foreach ($params as $pkg) {
  342. if ($this->installer->uninstall($pkg, $options)) {
  343. if ($this->config->get('verbose') > 0) {
  344. $this->ui->outputData("uninstall ok: $pkg", $command);
  345. }
  346. } else {
  347. return $this->raiseError("uninstall failed: $pkg");
  348. }
  349. }
  350. return true;
  351. }
  352. // }}}
  353. // }}}
  354. // {{{ doBundle()
  355. /*
  356. (cox) It just downloads and untars the package, does not do
  357. any check that the PEAR_Installer::_installFile() does.
  358. */
  359. function doBundle($command, $options, $params)
  360. {
  361. if (empty($this->installer)) {
  362. $this->installer = &new PEAR_Downloader($this->ui);
  363. }
  364. $installer = &$this->installer;
  365. if (sizeof($params) < 1) {
  366. return $this->raiseError("Please supply the package you want to bundle");
  367. }
  368. $pkgfile = $params[0];
  369. $need_download = false;
  370. if (preg_match('#^(http|ftp)://#', $pkgfile)) {
  371. $need_download = true;
  372. } elseif (!@is_file($pkgfile)) {
  373. if ($installer->validPackageName($pkgfile)) {
  374. $pkgfile = $installer->getPackageDownloadUrl($pkgfile);
  375. $need_download = true;
  376. } else {
  377. if (strlen($pkgfile)) {
  378. return $this->raiseError("Could not open the package file: $pkgfile");
  379. } else {
  380. return $this->raiseError("No package file given");
  381. }
  382. }
  383. }
  384. // Download package -----------------------------------------------
  385. if ($need_download) {
  386. $downloaddir = $installer->config->get('download_dir');
  387. if (empty($downloaddir)) {
  388. if (PEAR::isError($downloaddir = System::mktemp('-d'))) {
  389. return $downloaddir;
  390. }
  391. $installer->log(2, '+ tmp dir created at ' . $downloaddir);
  392. }
  393. $callback = $this->ui ? array(&$installer, '_downloadCallback') : null;
  394. $file = $installer->downloadHttp($pkgfile, $this->ui, $downloaddir, $callback);
  395. if (PEAR::isError($file)) {
  396. return $this->raiseError($file);
  397. }
  398. $pkgfile = $file;
  399. }
  400. // Parse xml file -----------------------------------------------
  401. $pkginfo = $installer->infoFromTgzFile($pkgfile);
  402. if (PEAR::isError($pkginfo)) {
  403. return $this->raiseError($pkginfo);
  404. }
  405. $installer->validatePackageInfo($pkginfo, $errors, $warnings);
  406. // XXX We allow warnings, do we have to do it?
  407. if (count($errors)) {
  408. if (empty($options['force'])) {
  409. return $this->raiseError("The following errors where found:\n".
  410. implode("\n", $errors));
  411. } else {
  412. $this->log(0, "warning : the following errors were found:\n".
  413. implode("\n", $errors));
  414. }
  415. }
  416. $pkgname = $pkginfo['package'];
  417. // Unpacking -------------------------------------------------
  418. if (isset($options['destination'])) {
  419. if (!is_dir($options['destination'])) {
  420. System::mkdir('-p ' . $options['destination']);
  421. }
  422. $dest = realpath($options['destination']);
  423. } else {
  424. $pwd = getcwd();
  425. if (is_dir($pwd . DIRECTORY_SEPARATOR . 'ext')) {
  426. $dest = $pwd . DIRECTORY_SEPARATOR . 'ext';
  427. } else {
  428. $dest = $pwd;
  429. }
  430. }
  431. $dest .= DIRECTORY_SEPARATOR . $pkgname;
  432. $orig = $pkgname . '-' . $pkginfo['version'];
  433. $tar = new Archive_Tar($pkgfile);
  434. if (!@$tar->extractModify($dest, $orig)) {
  435. return $this->raiseError("unable to unpack $pkgfile");
  436. }
  437. $this->ui->outputData("Package ready at '$dest'");
  438. // }}}
  439. }
  440. // }}}
  441. }
  442. ?>