Install.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  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. // | license@php.net so we can mail you a copy immediately. |
  15. // +----------------------------------------------------------------------+
  16. // | Author: Stig Sæther Bakken <ssb@php.net> |
  17. // +----------------------------------------------------------------------+
  18. //
  19. // $Id: Install.php,v 1.52 2004/01/08 17:33:13 sniper 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. $bn = basename($pkg['file']);
  292. $info = $this->installer->install($pkg['file'], $options, $this->config);
  293. if (is_array($info)) {
  294. if ($this->config->get('verbose') > 0) {
  295. $label = "$info[package] $info[version]";
  296. $out = array('data' => "$command ok: $label");
  297. if (isset($info['release_warnings'])) {
  298. $out['release_warnings'] = $info['release_warnings'];
  299. }
  300. $this->ui->outputData($out, $command);
  301. }
  302. } else {
  303. return $this->raiseError("$command failed");
  304. }
  305. }
  306. return true;
  307. }
  308. // }}}
  309. // {{{ doUninstall()
  310. function doUninstall($command, $options, $params)
  311. {
  312. if (empty($this->installer)) {
  313. $this->installer = &new PEAR_Installer($this->ui);
  314. }
  315. if (sizeof($params) < 1) {
  316. return $this->raiseError("Please supply the package(s) you want to uninstall");
  317. }
  318. include_once 'PEAR/Registry.php';
  319. $reg = new PEAR_Registry($this->config->get('php_dir'));
  320. $newparams = array();
  321. $badparams = array();
  322. foreach ($params as $pkg) {
  323. $info = $reg->packageInfo($pkg);
  324. if ($info === null) {
  325. $badparams[] = $pkg;
  326. } else {
  327. $newparams[] = $info;
  328. }
  329. }
  330. $this->installer->sortPkgDeps($newparams, true);
  331. $params = array();
  332. foreach($newparams as $info) {
  333. $params[] = $info['info']['package'];
  334. }
  335. $params = array_merge($params, $badparams);
  336. foreach ($params as $pkg) {
  337. if ($this->installer->uninstall($pkg, $options)) {
  338. if ($this->config->get('verbose') > 0) {
  339. $this->ui->outputData("uninstall ok: $pkg", $command);
  340. }
  341. } else {
  342. return $this->raiseError("uninstall failed: $pkg");
  343. }
  344. }
  345. return true;
  346. }
  347. // }}}
  348. // }}}
  349. // {{{ doBundle()
  350. /*
  351. (cox) It just downloads and untars the package, does not do
  352. any check that the PEAR_Installer::_installFile() does.
  353. */
  354. function doBundle($command, $options, $params)
  355. {
  356. if (empty($this->installer)) {
  357. $this->installer = &new PEAR_Downloader($this->ui);
  358. }
  359. $installer = &$this->installer;
  360. if (sizeof($params) < 1) {
  361. return $this->raiseError("Please supply the package you want to bundle");
  362. }
  363. $pkgfile = $params[0];
  364. $need_download = false;
  365. if (preg_match('#^(http|ftp)://#', $pkgfile)) {
  366. $need_download = true;
  367. } elseif (!@is_file($pkgfile)) {
  368. if ($installer->validPackageName($pkgfile)) {
  369. $pkgfile = $installer->getPackageDownloadUrl($pkgfile);
  370. $need_download = true;
  371. } else {
  372. if (strlen($pkgfile)) {
  373. return $this->raiseError("Could not open the package file: $pkgfile");
  374. } else {
  375. return $this->raiseError("No package file given");
  376. }
  377. }
  378. }
  379. // Download package -----------------------------------------------
  380. if ($need_download) {
  381. $downloaddir = $installer->config->get('download_dir');
  382. if (empty($downloaddir)) {
  383. if (PEAR::isError($downloaddir = System::mktemp('-d'))) {
  384. return $downloaddir;
  385. }
  386. $installer->log(2, '+ tmp dir created at ' . $downloaddir);
  387. }
  388. $callback = $this->ui ? array(&$installer, '_downloadCallback') : null;
  389. $file = $installer->downloadHttp($pkgfile, $this->ui, $downloaddir, $callback);
  390. if (PEAR::isError($file)) {
  391. return $this->raiseError($file);
  392. }
  393. $pkgfile = $file;
  394. }
  395. // Parse xml file -----------------------------------------------
  396. $pkginfo = $installer->infoFromTgzFile($pkgfile);
  397. if (PEAR::isError($pkginfo)) {
  398. return $this->raiseError($pkginfo);
  399. }
  400. $installer->validatePackageInfo($pkginfo, $errors, $warnings);
  401. // XXX We allow warnings, do we have to do it?
  402. if (count($errors)) {
  403. if (empty($options['force'])) {
  404. return $this->raiseError("The following errors where found:\n".
  405. implode("\n", $errors));
  406. } else {
  407. $this->log(0, "warning : the following errors were found:\n".
  408. implode("\n", $errors));
  409. }
  410. }
  411. $pkgname = $pkginfo['package'];
  412. // Unpacking -------------------------------------------------
  413. if (isset($options['destination'])) {
  414. if (!is_dir($options['destination'])) {
  415. System::mkdir('-p ' . $options['destination']);
  416. }
  417. $dest = realpath($options['destination']);
  418. } else {
  419. $pwd = getcwd();
  420. if (is_dir($pwd . DIRECTORY_SEPARATOR . 'ext')) {
  421. $dest = $pwd . DIRECTORY_SEPARATOR . 'ext';
  422. } else {
  423. $dest = $pwd;
  424. }
  425. }
  426. $dest .= DIRECTORY_SEPARATOR . $pkgname;
  427. $orig = $pkgname . '-' . $pkginfo['version'];
  428. $tar = new Archive_Tar($pkgfile);
  429. if (!@$tar->extractModify($dest, $orig)) {
  430. return $this->raiseError("unable to unpack $pkgfile");
  431. }
  432. $this->ui->outputData("Package ready at '$dest'");
  433. // }}}
  434. }
  435. // }}}
  436. }
  437. ?>