PageRenderTime 58ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/Library/php52/lib/php/PEAR/Dependency2.php

https://github.com/ktmud/MNPP
PHP | 1358 lines | 1026 code | 179 blank | 153 comment | 305 complexity | d4da6b74965e332e7f5dde3e391d4156 MD5 | raw file
Possible License(s): LGPL-2.1, BSD-2-Clause

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * PEAR_Dependency2, advanced dependency validation
  4. *
  5. * PHP versions 4 and 5
  6. *
  7. * @category pear
  8. * @package PEAR
  9. * @author Greg Beaver <cellog@php.net>
  10. * @copyright 1997-2009 The Authors
  11. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  12. * @version CVS: $Id: Dependency2.php 286494 2009-07-29 06:57:11Z dufuz $
  13. * @link http://pear.php.net/package/PEAR
  14. * @since File available since Release 1.4.0a1
  15. */
  16. /**
  17. * Required for the PEAR_VALIDATE_* constants
  18. */
  19. require_once 'PEAR/Validate.php';
  20. /**
  21. * Dependency check for PEAR packages
  22. *
  23. * This class handles both version 1.0 and 2.0 dependencies
  24. * WARNING: *any* changes to this class must be duplicated in the
  25. * test_PEAR_Dependency2 class found in tests/PEAR_Dependency2/setup.php.inc,
  26. * or unit tests will not actually validate the changes
  27. * @category pear
  28. * @package PEAR
  29. * @author Greg Beaver <cellog@php.net>
  30. * @copyright 1997-2009 The Authors
  31. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  32. * @version Release: 1.9.1
  33. * @link http://pear.php.net/package/PEAR
  34. * @since Class available since Release 1.4.0a1
  35. */
  36. class PEAR_Dependency2
  37. {
  38. /**
  39. * One of the PEAR_VALIDATE_* states
  40. * @see PEAR_VALIDATE_NORMAL
  41. * @var integer
  42. */
  43. var $_state;
  44. /**
  45. * Command-line options to install/upgrade/uninstall commands
  46. * @param array
  47. */
  48. var $_options;
  49. /**
  50. * @var OS_Guess
  51. */
  52. var $_os;
  53. /**
  54. * @var PEAR_Registry
  55. */
  56. var $_registry;
  57. /**
  58. * @var PEAR_Config
  59. */
  60. var $_config;
  61. /**
  62. * @var PEAR_DependencyDB
  63. */
  64. var $_dependencydb;
  65. /**
  66. * Output of PEAR_Registry::parsedPackageName()
  67. * @var array
  68. */
  69. var $_currentPackage;
  70. /**
  71. * @param PEAR_Config
  72. * @param array installation options
  73. * @param array format of PEAR_Registry::parsedPackageName()
  74. * @param int installation state (one of PEAR_VALIDATE_*)
  75. */
  76. function PEAR_Dependency2(&$config, $installoptions, $package,
  77. $state = PEAR_VALIDATE_INSTALLING)
  78. {
  79. $this->_config = &$config;
  80. if (!class_exists('PEAR_DependencyDB')) {
  81. require_once 'PEAR/DependencyDB.php';
  82. }
  83. if (isset($installoptions['packagingroot'])) {
  84. // make sure depdb is in the right location
  85. $config->setInstallRoot($installoptions['packagingroot']);
  86. }
  87. $this->_registry = &$config->getRegistry();
  88. $this->_dependencydb = &PEAR_DependencyDB::singleton($config);
  89. if (isset($installoptions['packagingroot'])) {
  90. $config->setInstallRoot(false);
  91. }
  92. $this->_options = $installoptions;
  93. $this->_state = $state;
  94. if (!class_exists('OS_Guess')) {
  95. require_once 'OS/Guess.php';
  96. }
  97. $this->_os = new OS_Guess;
  98. $this->_currentPackage = $package;
  99. }
  100. function _getExtraString($dep)
  101. {
  102. $extra = ' (';
  103. if (isset($dep['uri'])) {
  104. return '';
  105. }
  106. if (isset($dep['recommended'])) {
  107. $extra .= 'recommended version ' . $dep['recommended'];
  108. } else {
  109. if (isset($dep['min'])) {
  110. $extra .= 'version >= ' . $dep['min'];
  111. }
  112. if (isset($dep['max'])) {
  113. if ($extra != ' (') {
  114. $extra .= ', ';
  115. }
  116. $extra .= 'version <= ' . $dep['max'];
  117. }
  118. if (isset($dep['exclude'])) {
  119. if (!is_array($dep['exclude'])) {
  120. $dep['exclude'] = array($dep['exclude']);
  121. }
  122. if ($extra != ' (') {
  123. $extra .= ', ';
  124. }
  125. $extra .= 'excluded versions: ';
  126. foreach ($dep['exclude'] as $i => $exclude) {
  127. if ($i) {
  128. $extra .= ', ';
  129. }
  130. $extra .= $exclude;
  131. }
  132. }
  133. }
  134. $extra .= ')';
  135. if ($extra == ' ()') {
  136. $extra = '';
  137. }
  138. return $extra;
  139. }
  140. /**
  141. * This makes unit-testing a heck of a lot easier
  142. */
  143. function getPHP_OS()
  144. {
  145. return PHP_OS;
  146. }
  147. /**
  148. * This makes unit-testing a heck of a lot easier
  149. */
  150. function getsysname()
  151. {
  152. return $this->_os->getSysname();
  153. }
  154. /**
  155. * Specify a dependency on an OS. Use arch for detailed os/processor information
  156. *
  157. * There are two generic OS dependencies that will be the most common, unix and windows.
  158. * Other options are linux, freebsd, darwin (OS X), sunos, irix, hpux, aix
  159. */
  160. function validateOsDependency($dep)
  161. {
  162. if ($this->_state != PEAR_VALIDATE_INSTALLING && $this->_state != PEAR_VALIDATE_DOWNLOADING) {
  163. return true;
  164. }
  165. if ($dep['name'] == '*') {
  166. return true;
  167. }
  168. $not = isset($dep['conflicts']) ? true : false;
  169. switch (strtolower($dep['name'])) {
  170. case 'windows' :
  171. if ($not) {
  172. if (strtolower(substr($this->getPHP_OS(), 0, 3)) == 'win') {
  173. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  174. return $this->raiseError("Cannot install %s on Windows");
  175. }
  176. return $this->warning("warning: Cannot install %s on Windows");
  177. }
  178. } else {
  179. if (strtolower(substr($this->getPHP_OS(), 0, 3)) != 'win') {
  180. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  181. return $this->raiseError("Can only install %s on Windows");
  182. }
  183. return $this->warning("warning: Can only install %s on Windows");
  184. }
  185. }
  186. break;
  187. case 'unix' :
  188. $unices = array('linux', 'freebsd', 'darwin', 'sunos', 'irix', 'hpux', 'aix');
  189. if ($not) {
  190. if (in_array($this->getSysname(), $unices)) {
  191. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  192. return $this->raiseError("Cannot install %s on any Unix system");
  193. }
  194. return $this->warning( "warning: Cannot install %s on any Unix system");
  195. }
  196. } else {
  197. if (!in_array($this->getSysname(), $unices)) {
  198. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  199. return $this->raiseError("Can only install %s on a Unix system");
  200. }
  201. return $this->warning("warning: Can only install %s on a Unix system");
  202. }
  203. }
  204. break;
  205. default :
  206. if ($not) {
  207. if (strtolower($dep['name']) == strtolower($this->getSysname())) {
  208. if (!isset($this->_options['nodeps']) &&
  209. !isset($this->_options['force'])) {
  210. return $this->raiseError('Cannot install %s on ' . $dep['name'] .
  211. ' operating system');
  212. }
  213. return $this->warning('warning: Cannot install %s on ' .
  214. $dep['name'] . ' operating system');
  215. }
  216. } else {
  217. if (strtolower($dep['name']) != strtolower($this->getSysname())) {
  218. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  219. return $this->raiseError('Cannot install %s on ' .
  220. $this->getSysname() .
  221. ' operating system, can only install on ' . $dep['name']);
  222. }
  223. return $this->warning('warning: Cannot install %s on ' .
  224. $this->getSysname() .
  225. ' operating system, can only install on ' . $dep['name']);
  226. }
  227. }
  228. }
  229. return true;
  230. }
  231. /**
  232. * This makes unit-testing a heck of a lot easier
  233. */
  234. function matchSignature($pattern)
  235. {
  236. return $this->_os->matchSignature($pattern);
  237. }
  238. /**
  239. * Specify a complex dependency on an OS/processor/kernel version,
  240. * Use OS for simple operating system dependency.
  241. *
  242. * This is the only dependency that accepts an eregable pattern. The pattern
  243. * will be matched against the php_uname() output parsed by OS_Guess
  244. */
  245. function validateArchDependency($dep)
  246. {
  247. if ($this->_state != PEAR_VALIDATE_INSTALLING) {
  248. return true;
  249. }
  250. $not = isset($dep['conflicts']) ? true : false;
  251. if (!$this->matchSignature($dep['pattern'])) {
  252. if (!$not) {
  253. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  254. return $this->raiseError('%s Architecture dependency failed, does not ' .
  255. 'match "' . $dep['pattern'] . '"');
  256. }
  257. return $this->warning('warning: %s Architecture dependency failed, does ' .
  258. 'not match "' . $dep['pattern'] . '"');
  259. }
  260. return true;
  261. }
  262. if ($not) {
  263. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  264. return $this->raiseError('%s Architecture dependency failed, required "' .
  265. $dep['pattern'] . '"');
  266. }
  267. return $this->warning('warning: %s Architecture dependency failed, ' .
  268. 'required "' . $dep['pattern'] . '"');
  269. }
  270. return true;
  271. }
  272. /**
  273. * This makes unit-testing a heck of a lot easier
  274. */
  275. function extension_loaded($name)
  276. {
  277. return extension_loaded($name);
  278. }
  279. /**
  280. * This makes unit-testing a heck of a lot easier
  281. */
  282. function phpversion($name = null)
  283. {
  284. if ($name !== null) {
  285. return phpversion($name);
  286. }
  287. return phpversion();
  288. }
  289. function validateExtensionDependency($dep, $required = true)
  290. {
  291. if ($this->_state != PEAR_VALIDATE_INSTALLING &&
  292. $this->_state != PEAR_VALIDATE_DOWNLOADING) {
  293. return true;
  294. }
  295. $loaded = $this->extension_loaded($dep['name']);
  296. $extra = $this->_getExtraString($dep);
  297. if (isset($dep['exclude'])) {
  298. if (!is_array($dep['exclude'])) {
  299. $dep['exclude'] = array($dep['exclude']);
  300. }
  301. }
  302. if (!isset($dep['min']) && !isset($dep['max']) &&
  303. !isset($dep['recommended']) && !isset($dep['exclude'])
  304. ) {
  305. if ($loaded) {
  306. if (isset($dep['conflicts'])) {
  307. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  308. return $this->raiseError('%s conflicts with PHP extension "' .
  309. $dep['name'] . '"' . $extra);
  310. }
  311. return $this->warning('warning: %s conflicts with PHP extension "' .
  312. $dep['name'] . '"' . $extra);
  313. }
  314. return true;
  315. }
  316. if (isset($dep['conflicts'])) {
  317. return true;
  318. }
  319. if ($required) {
  320. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  321. return $this->raiseError('%s requires PHP extension "' .
  322. $dep['name'] . '"' . $extra);
  323. }
  324. return $this->warning('warning: %s requires PHP extension "' .
  325. $dep['name'] . '"' . $extra);
  326. }
  327. return $this->warning('%s can optionally use PHP extension "' .
  328. $dep['name'] . '"' . $extra);
  329. }
  330. if (!$loaded) {
  331. if (isset($dep['conflicts'])) {
  332. return true;
  333. }
  334. if (!$required) {
  335. return $this->warning('%s can optionally use PHP extension "' .
  336. $dep['name'] . '"' . $extra);
  337. }
  338. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  339. return $this->raiseError('%s requires PHP extension "' . $dep['name'] .
  340. '"' . $extra);
  341. }
  342. return $this->warning('warning: %s requires PHP extension "' . $dep['name'] .
  343. '"' . $extra);
  344. }
  345. $version = (string) $this->phpversion($dep['name']);
  346. if (empty($version)) {
  347. $version = '0';
  348. }
  349. $fail = false;
  350. if (isset($dep['min']) && !version_compare($version, $dep['min'], '>=')) {
  351. $fail = true;
  352. }
  353. if (isset($dep['max']) && !version_compare($version, $dep['max'], '<=')) {
  354. $fail = true;
  355. }
  356. if ($fail && !isset($dep['conflicts'])) {
  357. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  358. return $this->raiseError('%s requires PHP extension "' . $dep['name'] .
  359. '"' . $extra . ', installed version is ' . $version);
  360. }
  361. return $this->warning('warning: %s requires PHP extension "' . $dep['name'] .
  362. '"' . $extra . ', installed version is ' . $version);
  363. } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && isset($dep['conflicts'])) {
  364. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  365. return $this->raiseError('%s conflicts with PHP extension "' .
  366. $dep['name'] . '"' . $extra . ', installed version is ' . $version);
  367. }
  368. return $this->warning('warning: %s conflicts with PHP extension "' .
  369. $dep['name'] . '"' . $extra . ', installed version is ' . $version);
  370. }
  371. if (isset($dep['exclude'])) {
  372. foreach ($dep['exclude'] as $exclude) {
  373. if (version_compare($version, $exclude, '==')) {
  374. if (isset($dep['conflicts'])) {
  375. continue;
  376. }
  377. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  378. return $this->raiseError('%s is not compatible with PHP extension "' .
  379. $dep['name'] . '" version ' .
  380. $exclude);
  381. }
  382. return $this->warning('warning: %s is not compatible with PHP extension "' .
  383. $dep['name'] . '" version ' .
  384. $exclude);
  385. } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) {
  386. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  387. return $this->raiseError('%s conflicts with PHP extension "' .
  388. $dep['name'] . '"' . $extra . ', installed version is ' . $version);
  389. }
  390. return $this->warning('warning: %s conflicts with PHP extension "' .
  391. $dep['name'] . '"' . $extra . ', installed version is ' . $version);
  392. }
  393. }
  394. }
  395. if (isset($dep['recommended'])) {
  396. if (version_compare($version, $dep['recommended'], '==')) {
  397. return true;
  398. }
  399. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  400. return $this->raiseError('%s dependency: PHP extension ' . $dep['name'] .
  401. ' version "' . $version . '"' .
  402. ' is not the recommended version "' . $dep['recommended'] .
  403. '", but may be compatible, use --force to install');
  404. }
  405. return $this->warning('warning: %s dependency: PHP extension ' .
  406. $dep['name'] . ' version "' . $version . '"' .
  407. ' is not the recommended version "' . $dep['recommended'].'"');
  408. }
  409. return true;
  410. }
  411. function validatePhpDependency($dep)
  412. {
  413. if ($this->_state != PEAR_VALIDATE_INSTALLING &&
  414. $this->_state != PEAR_VALIDATE_DOWNLOADING) {
  415. return true;
  416. }
  417. $version = $this->phpversion();
  418. $extra = $this->_getExtraString($dep);
  419. if (isset($dep['exclude'])) {
  420. if (!is_array($dep['exclude'])) {
  421. $dep['exclude'] = array($dep['exclude']);
  422. }
  423. }
  424. if (isset($dep['min'])) {
  425. if (!version_compare($version, $dep['min'], '>=')) {
  426. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  427. return $this->raiseError('%s requires PHP' .
  428. $extra . ', installed version is ' . $version);
  429. }
  430. return $this->warning('warning: %s requires PHP' .
  431. $extra . ', installed version is ' . $version);
  432. }
  433. }
  434. if (isset($dep['max'])) {
  435. if (!version_compare($version, $dep['max'], '<=')) {
  436. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  437. return $this->raiseError('%s requires PHP' .
  438. $extra . ', installed version is ' . $version);
  439. }
  440. return $this->warning('warning: %s requires PHP' .
  441. $extra . ', installed version is ' . $version);
  442. }
  443. }
  444. if (isset($dep['exclude'])) {
  445. foreach ($dep['exclude'] as $exclude) {
  446. if (version_compare($version, $exclude, '==')) {
  447. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  448. return $this->raiseError('%s is not compatible with PHP version ' .
  449. $exclude);
  450. }
  451. return $this->warning(
  452. 'warning: %s is not compatible with PHP version ' .
  453. $exclude);
  454. }
  455. }
  456. }
  457. return true;
  458. }
  459. /**
  460. * This makes unit-testing a heck of a lot easier
  461. */
  462. function getPEARVersion()
  463. {
  464. return '1.9.1';
  465. }
  466. function validatePearinstallerDependency($dep)
  467. {
  468. $pearversion = $this->getPEARVersion();
  469. $extra = $this->_getExtraString($dep);
  470. if (isset($dep['exclude'])) {
  471. if (!is_array($dep['exclude'])) {
  472. $dep['exclude'] = array($dep['exclude']);
  473. }
  474. }
  475. if (version_compare($pearversion, $dep['min'], '<')) {
  476. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  477. return $this->raiseError('%s requires PEAR Installer' . $extra .
  478. ', installed version is ' . $pearversion);
  479. }
  480. return $this->warning('warning: %s requires PEAR Installer' . $extra .
  481. ', installed version is ' . $pearversion);
  482. }
  483. if (isset($dep['max'])) {
  484. if (version_compare($pearversion, $dep['max'], '>')) {
  485. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  486. return $this->raiseError('%s requires PEAR Installer' . $extra .
  487. ', installed version is ' . $pearversion);
  488. }
  489. return $this->warning('warning: %s requires PEAR Installer' . $extra .
  490. ', installed version is ' . $pearversion);
  491. }
  492. }
  493. if (isset($dep['exclude'])) {
  494. if (!isset($dep['exclude'][0])) {
  495. $dep['exclude'] = array($dep['exclude']);
  496. }
  497. foreach ($dep['exclude'] as $exclude) {
  498. if (version_compare($exclude, $pearversion, '==')) {
  499. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  500. return $this->raiseError('%s is not compatible with PEAR Installer ' .
  501. 'version ' . $exclude);
  502. }
  503. return $this->warning('warning: %s is not compatible with PEAR ' .
  504. 'Installer version ' . $exclude);
  505. }
  506. }
  507. }
  508. return true;
  509. }
  510. function validateSubpackageDependency($dep, $required, $params)
  511. {
  512. return $this->validatePackageDependency($dep, $required, $params);
  513. }
  514. /**
  515. * @param array dependency information (2.0 format)
  516. * @param boolean whether this is a required dependency
  517. * @param array a list of downloaded packages to be installed, if any
  518. * @param boolean if true, then deps on pear.php.net that fail will also check
  519. * against pecl.php.net packages to accomodate extensions that have
  520. * moved to pecl.php.net from pear.php.net
  521. */
  522. function validatePackageDependency($dep, $required, $params, $depv1 = false)
  523. {
  524. if ($this->_state != PEAR_VALIDATE_INSTALLING &&
  525. $this->_state != PEAR_VALIDATE_DOWNLOADING) {
  526. return true;
  527. }
  528. if (isset($dep['providesextension'])) {
  529. if ($this->extension_loaded($dep['providesextension'])) {
  530. $save = $dep;
  531. $subdep = $dep;
  532. $subdep['name'] = $subdep['providesextension'];
  533. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  534. $ret = $this->validateExtensionDependency($subdep, $required);
  535. PEAR::popErrorHandling();
  536. if (!PEAR::isError($ret)) {
  537. return true;
  538. }
  539. }
  540. }
  541. if ($this->_state == PEAR_VALIDATE_INSTALLING) {
  542. return $this->_validatePackageInstall($dep, $required, $depv1);
  543. }
  544. if ($this->_state == PEAR_VALIDATE_DOWNLOADING) {
  545. return $this->_validatePackageDownload($dep, $required, $params, $depv1);
  546. }
  547. }
  548. function _validatePackageDownload($dep, $required, $params, $depv1 = false)
  549. {
  550. $dep['package'] = $dep['name'];
  551. if (isset($dep['uri'])) {
  552. $dep['channel'] = '__uri';
  553. }
  554. $depname = $this->_registry->parsedPackageNameToString($dep, true);
  555. $found = false;
  556. foreach ($params as $param) {
  557. if ($param->isEqual(
  558. array('package' => $dep['name'],
  559. 'channel' => $dep['channel']))) {
  560. $found = true;
  561. break;
  562. }
  563. if ($depv1 && $dep['channel'] == 'pear.php.net') {
  564. if ($param->isEqual(
  565. array('package' => $dep['name'],
  566. 'channel' => 'pecl.php.net'))) {
  567. $found = true;
  568. break;
  569. }
  570. }
  571. }
  572. if (!$found && isset($dep['providesextension'])) {
  573. foreach ($params as $param) {
  574. if ($param->isExtension($dep['providesextension'])) {
  575. $found = true;
  576. break;
  577. }
  578. }
  579. }
  580. if ($found) {
  581. $version = $param->getVersion();
  582. $installed = false;
  583. $downloaded = true;
  584. } else {
  585. if ($this->_registry->packageExists($dep['name'], $dep['channel'])) {
  586. $installed = true;
  587. $downloaded = false;
  588. $version = $this->_registry->packageinfo($dep['name'], 'version',
  589. $dep['channel']);
  590. } else {
  591. if ($dep['channel'] == 'pecl.php.net' && $this->_registry->packageExists($dep['name'],
  592. 'pear.php.net')) {
  593. $installed = true;
  594. $downloaded = false;
  595. $version = $this->_registry->packageinfo($dep['name'], 'version',
  596. 'pear.php.net');
  597. } else {
  598. $version = 'not installed or downloaded';
  599. $installed = false;
  600. $downloaded = false;
  601. }
  602. }
  603. }
  604. $extra = $this->_getExtraString($dep);
  605. if (isset($dep['exclude']) && !is_array($dep['exclude'])) {
  606. $dep['exclude'] = array($dep['exclude']);
  607. }
  608. if (!isset($dep['min']) && !isset($dep['max']) &&
  609. !isset($dep['recommended']) && !isset($dep['exclude'])
  610. ) {
  611. if ($installed || $downloaded) {
  612. $installed = $installed ? 'installed' : 'downloaded';
  613. if (isset($dep['conflicts'])) {
  614. $rest = '';
  615. if ($version) {
  616. $rest = ", $installed version is " . $version;
  617. }
  618. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  619. return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra . $rest);
  620. }
  621. return $this->warning('warning: %s conflicts with package "' . $depname . '"' . $extra . $rest);
  622. }
  623. return true;
  624. }
  625. if (isset($dep['conflicts'])) {
  626. return true;
  627. }
  628. if ($required) {
  629. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  630. return $this->raiseError('%s requires package "' . $depname . '"' . $extra);
  631. }
  632. return $this->warning('warning: %s requires package "' . $depname . '"' . $extra);
  633. }
  634. return $this->warning('%s can optionally use package "' . $depname . '"' . $extra);
  635. }
  636. if (!$installed && !$downloaded) {
  637. if (isset($dep['conflicts'])) {
  638. return true;
  639. }
  640. if ($required) {
  641. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  642. return $this->raiseError('%s requires package "' . $depname . '"' . $extra);
  643. }
  644. return $this->warning('warning: %s requires package "' . $depname . '"' . $extra);
  645. }
  646. return $this->warning('%s can optionally use package "' . $depname . '"' . $extra);
  647. }
  648. $fail = false;
  649. if (isset($dep['min']) && version_compare($version, $dep['min'], '<')) {
  650. $fail = true;
  651. }
  652. if (isset($dep['max']) && version_compare($version, $dep['max'], '>')) {
  653. $fail = true;
  654. }
  655. if ($fail && !isset($dep['conflicts'])) {
  656. $installed = $installed ? 'installed' : 'downloaded';
  657. $dep['package'] = $dep['name'];
  658. $dep = $this->_registry->parsedPackageNameToString($dep, true);
  659. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  660. return $this->raiseError('%s requires package "' . $depname . '"' .
  661. $extra . ", $installed version is " . $version);
  662. }
  663. return $this->warning('warning: %s requires package "' . $depname . '"' .
  664. $extra . ", $installed version is " . $version);
  665. } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail &&
  666. isset($dep['conflicts']) && !isset($dep['exclude'])) {
  667. $installed = $installed ? 'installed' : 'downloaded';
  668. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  669. return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra .
  670. ", $installed version is " . $version);
  671. }
  672. return $this->warning('warning: %s conflicts with package "' . $depname . '"' .
  673. $extra . ", $installed version is " . $version);
  674. }
  675. if (isset($dep['exclude'])) {
  676. $installed = $installed ? 'installed' : 'downloaded';
  677. foreach ($dep['exclude'] as $exclude) {
  678. if (version_compare($version, $exclude, '==') && !isset($dep['conflicts'])) {
  679. if (!isset($this->_options['nodeps']) &&
  680. !isset($this->_options['force'])
  681. ) {
  682. return $this->raiseError('%s is not compatible with ' .
  683. $installed . ' package "' .
  684. $depname . '" version ' .
  685. $exclude);
  686. }
  687. return $this->warning('warning: %s is not compatible with ' .
  688. $installed . ' package "' .
  689. $depname . '" version ' .
  690. $exclude);
  691. } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) {
  692. $installed = $installed ? 'installed' : 'downloaded';
  693. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  694. return $this->raiseError('%s conflicts with package "' . $depname . '"' .
  695. $extra . ", $installed version is " . $version);
  696. }
  697. return $this->warning('warning: %s conflicts with package "' . $depname . '"' .
  698. $extra . ", $installed version is " . $version);
  699. }
  700. }
  701. }
  702. if (isset($dep['recommended'])) {
  703. $installed = $installed ? 'installed' : 'downloaded';
  704. if (version_compare($version, $dep['recommended'], '==')) {
  705. return true;
  706. }
  707. if (!$found && $installed) {
  708. $param = $this->_registry->getPackage($dep['name'], $dep['channel']);
  709. }
  710. if ($param) {
  711. $found = false;
  712. foreach ($params as $parent) {
  713. if ($parent->isEqual($this->_currentPackage)) {
  714. $found = true;
  715. break;
  716. }
  717. }
  718. if ($found) {
  719. if ($param->isCompatible($parent)) {
  720. return true;
  721. }
  722. } else { // this is for validPackage() calls
  723. $parent = $this->_registry->getPackage($this->_currentPackage['package'],
  724. $this->_currentPackage['channel']);
  725. if ($parent !== null && $param->isCompatible($parent)) {
  726. return true;
  727. }
  728. }
  729. }
  730. if (!isset($this->_options['nodeps']) && !isset($this->_options['force']) &&
  731. !isset($this->_options['loose'])
  732. ) {
  733. return $this->raiseError('%s dependency package "' . $depname .
  734. '" ' . $installed . ' version ' . $version .
  735. ' is not the recommended version ' . $dep['recommended'] .
  736. ', but may be compatible, use --force to install');
  737. }
  738. return $this->warning('warning: %s dependency package "' . $depname .
  739. '" ' . $installed . ' version ' . $version .
  740. ' is not the recommended version ' . $dep['recommended']);
  741. }
  742. return true;
  743. }
  744. function _validatePackageInstall($dep, $required, $depv1 = false)
  745. {
  746. return $this->_validatePackageDownload($dep, $required, array(), $depv1);
  747. }
  748. /**
  749. * Verify that uninstalling packages passed in to command line is OK.
  750. *
  751. * @param PEAR_Installer $dl
  752. * @return PEAR_Error|true
  753. */
  754. function validatePackageUninstall(&$dl)
  755. {
  756. if (PEAR::isError($this->_dependencydb)) {
  757. return $this->_dependencydb;
  758. }
  759. $params = array();
  760. // construct an array of "downloaded" packages to fool the package dependency checker
  761. // into using these to validate uninstalls of circular dependencies
  762. $downloaded = &$dl->getUninstallPackages();
  763. foreach ($downloaded as $i => $pf) {
  764. if (!class_exists('PEAR_Downloader_Package')) {
  765. require_once 'PEAR/Downloader/Package.php';
  766. }
  767. $dp = &new PEAR_Downloader_Package($dl);
  768. $dp->setPackageFile($downloaded[$i]);
  769. $params[$i] = &$dp;
  770. }
  771. // check cache
  772. $memyselfandI = strtolower($this->_currentPackage['channel']) . '/' .
  773. strtolower($this->_currentPackage['package']);
  774. if (isset($dl->___uninstall_package_cache)) {
  775. $badpackages = $dl->___uninstall_package_cache;
  776. if (isset($badpackages[$memyselfandI]['warnings'])) {
  777. foreach ($badpackages[$memyselfandI]['warnings'] as $warning) {
  778. $dl->log(0, $warning[0]);
  779. }
  780. }
  781. if (isset($badpackages[$memyselfandI]['errors'])) {
  782. foreach ($badpackages[$memyselfandI]['errors'] as $error) {
  783. if (is_array($error)) {
  784. $dl->log(0, $error[0]);
  785. } else {
  786. $dl->log(0, $error->getMessage());
  787. }
  788. }
  789. if (isset($this->_options['nodeps']) || isset($this->_options['force'])) {
  790. return $this->warning(
  791. 'warning: %s should not be uninstalled, other installed packages depend ' .
  792. 'on this package');
  793. }
  794. return $this->raiseError(
  795. '%s cannot be uninstalled, other installed packages depend on this package');
  796. }
  797. return true;
  798. }
  799. // first, list the immediate parents of each package to be uninstalled
  800. $perpackagelist = array();
  801. $allparents = array();
  802. foreach ($params as $i => $param) {
  803. $a = array(
  804. 'channel' => strtolower($param->getChannel()),
  805. 'package' => strtolower($param->getPackage())
  806. );
  807. $deps = $this->_dependencydb->getDependentPackages($a);
  808. if ($deps) {
  809. foreach ($deps as $d) {
  810. $pardeps = $this->_dependencydb->getDependencies($d);
  811. foreach ($pardeps as $dep) {
  812. if (strtolower($dep['dep']['channel']) == $a['channel'] &&
  813. strtolower($dep['dep']['name']) == $a['package']) {
  814. if (!isset($perpackagelist[$a['channel'] . '/' . $a['package']])) {
  815. $perpackagelist[$a['channel'] . '/' . $a['package']] = array();
  816. }
  817. $perpackagelist[$a['channel'] . '/' . $a['package']][]
  818. = array($d['channel'] . '/' . $d['package'], $dep);
  819. if (!isset($allparents[$d['channel'] . '/' . $d['package']])) {
  820. $allparents[$d['channel'] . '/' . $d['package']] = array();
  821. }
  822. if (!isset($allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']])) {
  823. $allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']] = array();
  824. }
  825. $allparents[$d['channel'] . '/' . $d['package']]
  826. [$a['channel'] . '/' . $a['package']][]
  827. = array($d, $dep);
  828. }
  829. }
  830. }
  831. }
  832. }
  833. // next, remove any packages from the parents list that are not installed
  834. $remove = array();
  835. foreach ($allparents as $parent => $d1) {
  836. foreach ($d1 as $d) {
  837. if ($this->_registry->packageExists($d[0][0]['package'], $d[0][0]['channel'])) {
  838. continue;
  839. }
  840. $remove[$parent] = true;
  841. }
  842. }
  843. // next remove any packages from the parents list that are not passed in for
  844. // uninstallation
  845. foreach ($allparents as $parent => $d1) {
  846. foreach ($d1 as $d) {
  847. foreach ($params as $param) {
  848. if (strtolower($param->getChannel()) == $d[0][0]['channel'] &&
  849. strtolower($param->getPackage()) == $d[0][0]['package']) {
  850. // found it
  851. continue 3;
  852. }
  853. }
  854. $remove[$parent] = true;
  855. }
  856. }
  857. // remove all packages whose dependencies fail
  858. // save which ones failed for error reporting
  859. $badchildren = array();
  860. do {
  861. $fail = false;
  862. foreach ($remove as $package => $unused) {
  863. if (!isset($allparents[$package])) {
  864. continue;
  865. }
  866. foreach ($allparents[$package] as $kid => $d1) {
  867. foreach ($d1 as $depinfo) {
  868. if ($depinfo[1]['type'] != 'optional') {
  869. if (isset($badchildren[$kid])) {
  870. continue;
  871. }
  872. $badchildren[$kid] = true;
  873. $remove[$kid] = true;
  874. $fail = true;
  875. continue 2;
  876. }
  877. }
  878. }
  879. if ($fail) {
  880. // start over, we removed some children
  881. continue 2;
  882. }
  883. }
  884. } while ($fail);
  885. // next, construct the list of packages that can't be uninstalled
  886. $badpackages = array();
  887. $save = $this->_currentPackage;
  888. foreach ($perpackagelist as $package => $packagedeps) {
  889. foreach ($packagedeps as $parent) {
  890. if (!isset($remove[$parent[0]])) {
  891. continue;
  892. }
  893. $packagename = $this->_registry->parsePackageName($parent[0]);
  894. $packagename['channel'] = $this->_registry->channelAlias($packagename['channel']);
  895. $pa = $this->_registry->getPackage($packagename['package'], $packagename['channel']);
  896. $packagename['package'] = $pa->getPackage();
  897. $this->_currentPackage = $packagename;
  898. // parent is not present in uninstall list, make sure we can actually
  899. // uninstall it (parent dep is optional)
  900. $parentname['channel'] = $this->_registry->channelAlias($parent[1]['dep']['channel']);
  901. $pa = $this->_registry->getPackage($parent[1]['dep']['name'], $parent[1]['dep']['channel']);
  902. $parentname['package'] = $pa->getPackage();
  903. $parent[1]['dep']['package'] = $parentname['package'];
  904. $parent[1]['dep']['channel'] = $parentname['channel'];
  905. if ($parent[1]['type'] == 'optional') {
  906. $test = $this->_validatePackageUninstall($parent[1]['dep'], false, $dl);
  907. if ($test !== true) {
  908. $badpackages[$package]['warnings'][] = $test;
  909. }
  910. } else {
  911. $test = $this->_validatePackageUninstall($parent[1]['dep'], true, $dl);
  912. if ($test !== true) {
  913. $badpackages[$package]['errors'][] = $test;
  914. }
  915. }
  916. }
  917. }
  918. $this->_currentPackage = $save;
  919. $dl->___uninstall_package_cache = $badpackages;
  920. if (isset($badpackages[$memyselfandI])) {
  921. if (isset($badpackages[$memyselfandI]['warnings'])) {
  922. foreach ($badpackages[$memyselfandI]['warnings'] as $warning) {
  923. $dl->log(0, $warning[0]);
  924. }
  925. }
  926. if (isset($badpackages[$memyselfandI]['errors'])) {
  927. foreach ($badpackages[$memyselfandI]['errors'] as $error) {
  928. if (is_array($error)) {
  929. $dl->log(0, $error[0]);
  930. } else {
  931. $dl->log(0, $error->getMessage());
  932. }
  933. }
  934. if (isset($this->_options['nodeps']) || isset($this->_options['force'])) {
  935. return $this->warning(
  936. 'warning: %s should not be uninstalled, other installed packages depend ' .
  937. 'on this package');
  938. }
  939. return $this->raiseError(
  940. '%s cannot be uninstalled, other installed packages depend on this package');
  941. }
  942. }
  943. return true;
  944. }
  945. function _validatePackageUninstall($dep, $required, $dl)
  946. {
  947. $depname = $this->_registry->parsedPackageNameToString($dep, true);
  948. $version = $this->_registry->packageinfo($dep['package'], 'version', $dep['channel']);
  949. if (!$version) {
  950. return true;
  951. }
  952. $extra = $this->_getExtraString($dep);
  953. if (isset($dep['exclude']) && !is_array($dep['exclude'])) {
  954. $dep['exclude'] = array($dep['exclude']);
  955. }
  956. if (isset($dep['conflicts'])) {
  957. return true; // uninstall OK - these packages conflict (probably installed with --force)
  958. }
  959. if (!isset($dep['min']) && !isset($dep['max'])) {
  960. if (!$required) {
  961. return $this->warning('"' . $depname . '" can be optionally used by ' .
  962. 'installed package %s' . $extra);
  963. }
  964. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  965. return $this->raiseError('"' . $depname . '" is required by ' .
  966. 'installed package %s' . $extra);
  967. }
  968. return $this->warning('warning: "' . $depname . '" is required by ' .
  969. 'installed package %s' . $extra);
  970. }
  971. $fail = false;
  972. if (isset($dep['min']) && version_compare($version, $dep['min'], '>=')) {
  973. $fail = true;
  974. }
  975. if (isset($dep['max']) && version_compare($version, $dep['max'], '<=')) {
  976. $fail = true;
  977. }
  978. // we re-use this variable, preserve the original value
  979. $saverequired = $required;
  980. if (!$required) {
  981. return $this->warning($depname . $extra . ' can be optionally used by installed package' .
  982. ' "%s"');
  983. }
  984. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  985. return $this->raiseError($depname . $extra . ' is required by installed package' .
  986. ' "%s"');
  987. }
  988. return $this->raiseError('warning: ' . $depname . $extra .
  989. ' is required by installed package "%s"');
  990. }
  991. /**
  992. * validate a downloaded package against installed packages
  993. *
  994. * As of PEAR 1.4.3, this will only validate
  995. *
  996. * @param array|PEAR_Downloader_Package|PEAR_PackageFile_v1|PEAR_PackageFile_v2
  997. * $pkg package identifier (either
  998. * array('package' => blah, 'channel' => blah) or an array with
  999. * index 'info' referencing an object)
  1000. * @param PEAR_Downloader $dl
  1001. * @param array $params full list of packages to install
  1002. * @return true|PEAR_Error
  1003. */
  1004. function validatePackage($pkg, &$dl, $params = array())
  1005. {
  1006. if (is_array($pkg) && isset($pkg['info'])) {
  1007. $deps = $this->_dependencydb->getDependentPackageDependencies($pkg['info']);
  1008. } else {
  1009. $deps = $this->_dependencydb->getDependentPackageDependencies($pkg);
  1010. }
  1011. $fail = false;
  1012. if ($deps) {
  1013. if (!class_exists('PEAR_Downloader_Package')) {
  1014. require_once 'PEAR/Downloader/Package.php';
  1015. }
  1016. $dp = &new PEAR_Downloader_Package($dl);
  1017. if (is_object($pkg)) {
  1018. $dp->setPackageFile($pkg);
  1019. } else {
  1020. $dp->setDownloadURL($pkg);
  1021. }
  1022. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  1023. foreach ($deps as $channel => $info) {
  1024. foreach ($info as $package => $ds) {
  1025. foreach ($params as $packd) {
  1026. if (strtolower($packd->getPackage()) == strtolower($package) &&
  1027. $packd->getChannel() == $channel) {
  1028. $dl->log(3, 'skipping installed package check of "' .
  1029. $this->_registry->parsedPackageNameToString(
  1030. array('channel' => $channel, 'package' => $package),
  1031. true) .
  1032. '", version "' . $packd->getVersion() . '" will be ' .
  1033. 'downloaded and installed');
  1034. continue 2; // jump to next package
  1035. }
  1036. }
  1037. foreach ($ds as $d) {
  1038. $checker = &new PEAR_Dependency2($this->_config, $this->_options,
  1039. array('channel' => $channel, 'package' => $package), $this->_state);
  1040. $dep = $d['dep'];
  1041. $required = $d['type'] == 'required';
  1042. $ret = $checker->_validatePackageDownload($dep, $required, array(&$dp));
  1043. if (is_array($ret)) {
  1044. $dl->log(0, $ret[0]);
  1045. } elseif (PEAR::isError($ret)) {
  1046. $dl->log(0, $ret->getMessage());
  1047. $fail = true;
  1048. }
  1049. }
  1050. }
  1051. }
  1052. PEAR::popErrorHandling();
  1053. }
  1054. if ($fail) {
  1055. return $this->raiseError(
  1056. '%s cannot be installed, conflicts with installed packages');
  1057. }
  1058. return true;
  1059. }
  1060. /**
  1061. * validate a package.xml 1.0 dependency
  1062. */
  1063. function validateDependency1($dep, $params = array())
  1064. {
  1065. if (!isset($dep['optional'])) {
  1066. $dep['optional'] = 'no';
  1067. }
  1068. list($newdep, $type) = $this->normalizeDep($dep);
  1069. if (!$newdep) {
  1070. return $this->raiseError("Invalid Dependency");
  1071. }
  1072. if (method_exists($this, "validate{$type}Dependency")) {
  1073. return $this->{"validate{$type}Dependency"}($newdep, $dep['optional'] == 'no',
  1074. $params, true);
  1075. }
  1076. }
  1077. /**
  1078. * Convert a 1.0 dep into a 2.0 dep
  1079. */
  1080. function normalizeDep($dep)
  1081. {
  1082. $types = array(
  1083. 'pkg' => 'Package',
  1084. 'ext' => 'Extension',
  1085. 'os' => 'Os',
  1086. 'php' => 'Php'
  1087. );
  1088. if (!isset($types[$dep['type']])) {
  1089. return array(false, false);
  1090. }
  1091. $type = $types[$dep['type']];
  1092. $newdep = array();
  1093. switch ($type) {
  1094. case 'Package' :
  1095. $newdep['channel'] = 'pear.php.net';
  1096. case 'Extension' :
  1097. case 'Os' :
  1098. $newdep['name'] = $dep['name'];
  1099. break;
  1100. }
  1101. $dep['rel'] = PEAR_Dependency2::signOperator($dep['rel']);
  1102. switch ($dep['rel']) {
  1103. case 'has' :
  1104. return array($newdep, $type);
  1105. break;
  1106. case 'not' :
  1107. $newdep['conflicts'] = true;
  1108. break;
  1109. case '>=' :
  1110. case '>' :
  1111. $newdep['min'] = $dep['version'];
  1112. if ($dep['rel'] == '>') {
  1113. $newdep['exclude'] = $dep['version'];
  1114. }
  1115. break;
  1116. case '<=' :
  1117. case '<' :
  1118. $newdep['max'] = $dep['version'];
  1119. if ($dep['rel'] == '<') {
  1120. $newdep['exclude'] = $dep['version'];
  1121. }
  1122. break;
  1123. case 'ne' :
  1124. case '!=' :
  1125. $newdep['min'] = '0';
  1126. $newdep['max'] = '100000';
  1127. $newdep['exclude'] = $dep['version'];
  1128. break;
  1129. case '==' :
  1130. $newdep['min'] = $dep['version'];
  1131. $newdep['max'] = $dep['version'];
  1132. break;
  1133. }
  1134. if ($type == 'Php') {
  1135. if (!isset($newdep['min'])) {
  1136. $newdep['min'] = '4.4.0';
  1137. }
  1138. if (!isset($newdep['max'])) {
  1139. $newdep['max'] = '6.0.0';
  1140. }
  1141. }
  1142. return array($newdep, $type);
  1143. }
  1144. /**
  1145. * Converts text comparing operators to them sign equivalents
  1146. *
  1147. * Example: 'ge' to '>='
  1148. *
  1149. * @access public
  1150. * @param string Operator
  1151. * @return string Sign equivalent
  1152. */
  1153. function signOperator($operator)
  1154. {
  1155. switch($operator) {
  1156. case 'lt': return '<';
  1157. case 'le': return '<=';
  1158. case 'gt': return '>';
  1159. case 'ge': return '>=';
  1160. case 'eq': return '==';
  1161. case 'ne': return '!=';

Large files files are truncated, but you can click here to view the full file