Package.php 74 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981
  1. <?php
  2. /**
  3. * PEAR_Downloader_Package
  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. * @link http://pear.php.net/package/PEAR
  13. * @since File available since Release 1.4.0a1
  14. */
  15. /**
  16. * Error code when parameter initialization fails because no releases
  17. * exist within preferred_state, but releases do exist
  18. */
  19. define('PEAR_DOWNLOADER_PACKAGE_STATE', -1003);
  20. /**
  21. * Error code when parameter initialization fails because no releases
  22. * exist that will work with the existing PHP version
  23. */
  24. define('PEAR_DOWNLOADER_PACKAGE_PHPVERSION', -1004);
  25. /**
  26. * Coordinates download parameters and manages their dependencies
  27. * prior to downloading them.
  28. *
  29. * Input can come from three sources:
  30. *
  31. * - local files (archives or package.xml)
  32. * - remote files (downloadable urls)
  33. * - abstract package names
  34. *
  35. * The first two elements are handled cleanly by PEAR_PackageFile, but the third requires
  36. * accessing pearweb's xml-rpc interface to determine necessary dependencies, and the
  37. * format returned of dependencies is slightly different from that used in package.xml.
  38. *
  39. * This class hides the differences between these elements, and makes automatic
  40. * dependency resolution a piece of cake. It also manages conflicts when
  41. * two classes depend on incompatible dependencies, or differing versions of the same
  42. * package dependency. In addition, download will not be attempted if the php version is
  43. * not supported, PEAR installer version is not supported, or non-PECL extensions are not
  44. * installed.
  45. * @category pear
  46. * @package PEAR
  47. * @author Greg Beaver <cellog@php.net>
  48. * @copyright 1997-2009 The Authors
  49. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  50. * @version Release: 1.10.10
  51. * @link http://pear.php.net/package/PEAR
  52. * @since Class available since Release 1.4.0a1
  53. */
  54. class PEAR_Downloader_Package
  55. {
  56. /**
  57. * @var PEAR_Downloader
  58. */
  59. var $_downloader;
  60. /**
  61. * @var PEAR_Config
  62. */
  63. var $_config;
  64. /**
  65. * @var PEAR_Registry
  66. */
  67. var $_registry;
  68. /**
  69. * Used to implement packagingroot properly
  70. * @var PEAR_Registry
  71. */
  72. var $_installRegistry;
  73. /**
  74. * @var PEAR_PackageFile_v1|PEAR_PackageFile|v2
  75. */
  76. var $_packagefile;
  77. /**
  78. * @var array
  79. */
  80. var $_parsedname;
  81. /**
  82. * @var array
  83. */
  84. var $_downloadURL;
  85. /**
  86. * @var array
  87. */
  88. var $_downloadDeps = array();
  89. /**
  90. * @var boolean
  91. */
  92. var $_valid = false;
  93. /**
  94. * @var boolean
  95. */
  96. var $_analyzed = false;
  97. /**
  98. * if this or a parent package was invoked with Package-state, this is set to the
  99. * state variable.
  100. *
  101. * This allows temporary reassignment of preferred_state for a parent package and all of
  102. * its dependencies.
  103. * @var string|false
  104. */
  105. var $_explicitState = false;
  106. /**
  107. * If this package is invoked with Package#group, this variable will be true
  108. */
  109. var $_explicitGroup = false;
  110. /**
  111. * Package type local|url
  112. * @var string
  113. */
  114. var $_type;
  115. /**
  116. * Contents of package.xml, if downloaded from a remote channel
  117. * @var string|false
  118. * @access private
  119. */
  120. var $_rawpackagefile;
  121. /**
  122. * @var boolean
  123. * @access private
  124. */
  125. var $_validated = false;
  126. /**
  127. * @param PEAR_Downloader
  128. */
  129. function __construct(&$downloader)
  130. {
  131. $this->_downloader = &$downloader;
  132. $this->_config = &$this->_downloader->config;
  133. $this->_registry = &$this->_config->getRegistry();
  134. $options = $downloader->getOptions();
  135. if (isset($options['packagingroot'])) {
  136. $this->_config->setInstallRoot($options['packagingroot']);
  137. $this->_installRegistry = &$this->_config->getRegistry();
  138. $this->_config->setInstallRoot(false);
  139. } else {
  140. $this->_installRegistry = &$this->_registry;
  141. }
  142. $this->_valid = $this->_analyzed = false;
  143. }
  144. /**
  145. * Parse the input and determine whether this is a local file, a remote uri, or an
  146. * abstract package name.
  147. *
  148. * This is the heart of the PEAR_Downloader_Package(), and is used in
  149. * {@link PEAR_Downloader::download()}
  150. * @param string
  151. * @return bool|PEAR_Error
  152. */
  153. function initialize($param)
  154. {
  155. $origErr = $this->_fromFile($param);
  156. if ($this->_valid) {
  157. return true;
  158. }
  159. $options = $this->_downloader->getOptions();
  160. if (isset($options['offline'])) {
  161. if (PEAR::isError($origErr) && !isset($options['soft'])) {
  162. foreach ($origErr->getUserInfo() as $userInfo) {
  163. if (isset($userInfo['message'])) {
  164. $this->_downloader->log(0, $userInfo['message']);
  165. }
  166. }
  167. $this->_downloader->log(0, $origErr->getMessage());
  168. }
  169. return PEAR::raiseError('Cannot download non-local package "' . $param . '"');
  170. }
  171. $err = $this->_fromUrl($param);
  172. if (PEAR::isError($err) || !$this->_valid) {
  173. if ($this->_type == 'url') {
  174. if (PEAR::isError($err) && !isset($options['soft'])) {
  175. $this->_downloader->log(0, $err->getMessage());
  176. }
  177. return PEAR::raiseError("Invalid or missing remote package file");
  178. }
  179. $err = $this->_fromString($param);
  180. if (PEAR::isError($err) || !$this->_valid) {
  181. if (PEAR::isError($err) && $err->getCode() == PEAR_DOWNLOADER_PACKAGE_STATE) {
  182. return false; // instruct the downloader to silently skip
  183. }
  184. if (isset($this->_type) && $this->_type == 'local' && PEAR::isError($origErr)) {
  185. if (is_array($origErr->getUserInfo())) {
  186. foreach ($origErr->getUserInfo() as $err) {
  187. if (is_array($err)) {
  188. $err = $err['message'];
  189. }
  190. if (!isset($options['soft'])) {
  191. $this->_downloader->log(0, $err);
  192. }
  193. }
  194. }
  195. if (!isset($options['soft'])) {
  196. $this->_downloader->log(0, $origErr->getMessage());
  197. }
  198. if (is_array($param)) {
  199. $param = $this->_registry->parsedPackageNameToString($param, true);
  200. }
  201. if (!isset($options['soft'])) {
  202. $this->_downloader->log(2, "Cannot initialize '$param', invalid or missing package file");
  203. }
  204. // Passing no message back - already logged above
  205. return PEAR::raiseError();
  206. }
  207. if (PEAR::isError($err) && !isset($options['soft'])) {
  208. $this->_downloader->log(0, $err->getMessage());
  209. }
  210. if (is_array($param)) {
  211. $param = $this->_registry->parsedPackageNameToString($param, true);
  212. }
  213. if (!isset($options['soft'])) {
  214. $this->_downloader->log(2, "Cannot initialize '$param', invalid or missing package file");
  215. }
  216. // Passing no message back - already logged above
  217. return PEAR::raiseError();
  218. }
  219. }
  220. return true;
  221. }
  222. /**
  223. * Retrieve any non-local packages
  224. * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|PEAR_Error
  225. */
  226. function &download()
  227. {
  228. if (isset($this->_packagefile)) {
  229. return $this->_packagefile;
  230. }
  231. if (isset($this->_downloadURL['url'])) {
  232. $this->_isvalid = false;
  233. $info = $this->getParsedPackage();
  234. foreach ($info as $i => $p) {
  235. $info[$i] = strtolower($p);
  236. }
  237. $err = $this->_fromUrl($this->_downloadURL['url'],
  238. $this->_registry->parsedPackageNameToString($this->_parsedname, true));
  239. $newinfo = $this->getParsedPackage();
  240. foreach ($newinfo as $i => $p) {
  241. $newinfo[$i] = strtolower($p);
  242. }
  243. if ($info != $newinfo) {
  244. do {
  245. if ($info['channel'] == 'pecl.php.net' && $newinfo['channel'] == 'pear.php.net') {
  246. $info['channel'] = 'pear.php.net';
  247. if ($info == $newinfo) {
  248. // skip the channel check if a pecl package says it's a PEAR package
  249. break;
  250. }
  251. }
  252. if ($info['channel'] == 'pear.php.net' && $newinfo['channel'] == 'pecl.php.net') {
  253. $info['channel'] = 'pecl.php.net';
  254. if ($info == $newinfo) {
  255. // skip the channel check if a pecl package says it's a PEAR package
  256. break;
  257. }
  258. }
  259. return PEAR::raiseError('CRITICAL ERROR: We are ' .
  260. $this->_registry->parsedPackageNameToString($info) . ', but the file ' .
  261. 'downloaded claims to be ' .
  262. $this->_registry->parsedPackageNameToString($this->getParsedPackage()));
  263. } while (false);
  264. }
  265. if (PEAR::isError($err) || !$this->_valid) {
  266. return $err;
  267. }
  268. }
  269. $this->_type = 'local';
  270. return $this->_packagefile;
  271. }
  272. function &getPackageFile()
  273. {
  274. return $this->_packagefile;
  275. }
  276. function &getDownloader()
  277. {
  278. return $this->_downloader;
  279. }
  280. function getType()
  281. {
  282. return $this->_type;
  283. }
  284. /**
  285. * Like {@link initialize()}, but operates on a dependency
  286. */
  287. function fromDepURL($dep)
  288. {
  289. $this->_downloadURL = $dep;
  290. if (isset($dep['uri'])) {
  291. $options = $this->_downloader->getOptions();
  292. if (!extension_loaded("zlib") || isset($options['nocompress'])) {
  293. $ext = '.tar';
  294. } else {
  295. $ext = '.tgz';
  296. }
  297. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  298. $err = $this->_fromUrl($dep['uri'] . $ext);
  299. PEAR::popErrorHandling();
  300. if (PEAR::isError($err)) {
  301. if (!isset($options['soft'])) {
  302. $this->_downloader->log(0, $err->getMessage());
  303. }
  304. return PEAR::raiseError('Invalid uri dependency "' . $dep['uri'] . $ext . '", ' .
  305. 'cannot download');
  306. }
  307. } else {
  308. $this->_parsedname =
  309. array(
  310. 'package' => $dep['info']->getPackage(),
  311. 'channel' => $dep['info']->getChannel(),
  312. 'version' => $dep['version']
  313. );
  314. if (!isset($dep['nodefault'])) {
  315. $this->_parsedname['group'] = 'default'; // download the default dependency group
  316. $this->_explicitGroup = false;
  317. }
  318. $this->_rawpackagefile = $dep['raw'];
  319. }
  320. }
  321. function detectDependencies($params)
  322. {
  323. $options = $this->_downloader->getOptions();
  324. if (isset($options['downloadonly'])) {
  325. return;
  326. }
  327. if (isset($options['offline'])) {
  328. $this->_downloader->log(3, 'Skipping dependency download check, --offline specified');
  329. return;
  330. }
  331. $pname = $this->getParsedPackage();
  332. if (!$pname) {
  333. return;
  334. }
  335. $deps = $this->getDeps();
  336. if (!$deps) {
  337. return;
  338. }
  339. if (isset($deps['required'])) { // package.xml 2.0
  340. return $this->_detect2($deps, $pname, $options, $params);
  341. }
  342. return $this->_detect1($deps, $pname, $options, $params);
  343. }
  344. function setValidated()
  345. {
  346. $this->_validated = true;
  347. }
  348. function alreadyValidated()
  349. {
  350. return $this->_validated;
  351. }
  352. /**
  353. * Remove packages to be downloaded that are already installed
  354. * @param array of PEAR_Downloader_Package objects
  355. */
  356. public static function removeInstalled(&$params)
  357. {
  358. if (!isset($params[0])) {
  359. return;
  360. }
  361. $options = $params[0]->_downloader->getOptions();
  362. if (!isset($options['downloadonly'])) {
  363. foreach ($params as $i => $param) {
  364. $package = $param->getPackage();
  365. $channel = $param->getChannel();
  366. // remove self if already installed with this version
  367. // this does not need any pecl magic - we only remove exact matches
  368. if ($param->_installRegistry->packageExists($package, $channel)) {
  369. $packageVersion = $param->_installRegistry->packageInfo($package, 'version', $channel);
  370. if (version_compare($packageVersion, $param->getVersion(), '==')) {
  371. if (!isset($options['force']) && !isset($options['packagingroot'])) {
  372. $info = $param->getParsedPackage();
  373. unset($info['version']);
  374. unset($info['state']);
  375. if (!isset($options['soft'])) {
  376. $param->_downloader->log(1, 'Skipping package "' .
  377. $param->getShortName() .
  378. '", already installed as version ' . $packageVersion);
  379. }
  380. $params[$i] = false;
  381. }
  382. } elseif (!isset($options['force']) && !isset($options['upgrade']) &&
  383. !isset($options['soft']) && !isset($options['packagingroot'])) {
  384. $info = $param->getParsedPackage();
  385. $param->_downloader->log(1, 'Skipping package "' .
  386. $param->getShortName() .
  387. '", already installed as version ' . $packageVersion);
  388. $params[$i] = false;
  389. }
  390. }
  391. }
  392. }
  393. PEAR_Downloader_Package::removeDuplicates($params);
  394. }
  395. function _detect2($deps, $pname, $options, $params)
  396. {
  397. $this->_downloadDeps = array();
  398. $groupnotfound = false;
  399. foreach (array('package', 'subpackage') as $packagetype) {
  400. // get required dependency group
  401. if (isset($deps['required'][$packagetype])) {
  402. if (isset($deps['required'][$packagetype][0])) {
  403. foreach ($deps['required'][$packagetype] as $dep) {
  404. if (isset($dep['conflicts'])) {
  405. // skip any package that this package conflicts with
  406. continue;
  407. }
  408. $ret = $this->_detect2Dep($dep, $pname, 'required', $params);
  409. if (is_array($ret)) {
  410. $this->_downloadDeps[] = $ret;
  411. } elseif (PEAR::isError($ret) && !isset($options['soft'])) {
  412. $this->_downloader->log(0, $ret->getMessage());
  413. }
  414. }
  415. } else {
  416. $dep = $deps['required'][$packagetype];
  417. if (!isset($dep['conflicts'])) {
  418. // skip any package that this package conflicts with
  419. $ret = $this->_detect2Dep($dep, $pname, 'required', $params);
  420. if (is_array($ret)) {
  421. $this->_downloadDeps[] = $ret;
  422. } elseif (PEAR::isError($ret) && !isset($options['soft'])) {
  423. $this->_downloader->log(0, $ret->getMessage());
  424. }
  425. }
  426. }
  427. }
  428. // get optional dependency group, if any
  429. if (isset($deps['optional'][$packagetype])) {
  430. $skipnames = array();
  431. if (!isset($deps['optional'][$packagetype][0])) {
  432. $deps['optional'][$packagetype] = array($deps['optional'][$packagetype]);
  433. }
  434. foreach ($deps['optional'][$packagetype] as $dep) {
  435. $skip = false;
  436. if (!isset($options['alldeps'])) {
  437. $dep['package'] = $dep['name'];
  438. if (!isset($options['soft'])) {
  439. $this->_downloader->log(3, 'Notice: package "' .
  440. $this->_registry->parsedPackageNameToString($this->getParsedPackage(),
  441. true) . '" optional dependency "' .
  442. $this->_registry->parsedPackageNameToString(array('package' =>
  443. $dep['name'], 'channel' => 'pear.php.net'), true) .
  444. '" will not be automatically downloaded');
  445. }
  446. $skipnames[] = $this->_registry->parsedPackageNameToString($dep, true);
  447. $skip = true;
  448. unset($dep['package']);
  449. }
  450. $ret = $this->_detect2Dep($dep, $pname, 'optional', $params);
  451. if (PEAR::isError($ret) && !isset($options['soft'])) {
  452. $this->_downloader->log(0, $ret->getMessage());
  453. }
  454. if (!$ret) {
  455. $dep['package'] = $dep['name'];
  456. $skip = count($skipnames) ?
  457. $skipnames[count($skipnames) - 1] : '';
  458. if ($skip ==
  459. $this->_registry->parsedPackageNameToString($dep, true)) {
  460. array_pop($skipnames);
  461. }
  462. }
  463. if (!$skip && is_array($ret)) {
  464. $this->_downloadDeps[] = $ret;
  465. }
  466. }
  467. if (count($skipnames)) {
  468. if (!isset($options['soft'])) {
  469. $this->_downloader->log(1, 'Did not download optional dependencies: ' .
  470. implode(', ', $skipnames) .
  471. ', use --alldeps to download automatically');
  472. }
  473. }
  474. }
  475. // get requested dependency group, if any
  476. $groupname = $this->getGroup();
  477. $explicit = $this->_explicitGroup;
  478. if (!$groupname) {
  479. if (!$this->canDefault()) {
  480. continue;
  481. }
  482. $groupname = 'default'; // try the default dependency group
  483. }
  484. if ($groupnotfound) {
  485. continue;
  486. }
  487. if (isset($deps['group'])) {
  488. if (isset($deps['group']['attribs'])) {
  489. if (strtolower($deps['group']['attribs']['name']) == strtolower($groupname)) {
  490. $group = $deps['group'];
  491. } elseif ($explicit) {
  492. if (!isset($options['soft'])) {
  493. $this->_downloader->log(0, 'Warning: package "' .
  494. $this->_registry->parsedPackageNameToString($pname, true) .
  495. '" has no dependency ' . 'group named "' . $groupname . '"');
  496. }
  497. $groupnotfound = true;
  498. continue;
  499. }
  500. } else {
  501. $found = false;
  502. foreach ($deps['group'] as $group) {
  503. if (strtolower($group['attribs']['name']) == strtolower($groupname)) {
  504. $found = true;
  505. break;
  506. }
  507. }
  508. if (!$found) {
  509. if ($explicit) {
  510. if (!isset($options['soft'])) {
  511. $this->_downloader->log(0, 'Warning: package "' .
  512. $this->_registry->parsedPackageNameToString($pname, true) .
  513. '" has no dependency ' . 'group named "' . $groupname . '"');
  514. }
  515. }
  516. $groupnotfound = true;
  517. continue;
  518. }
  519. }
  520. }
  521. if (isset($group) && isset($group[$packagetype])) {
  522. if (isset($group[$packagetype][0])) {
  523. foreach ($group[$packagetype] as $dep) {
  524. $ret = $this->_detect2Dep($dep, $pname, 'dependency group "' .
  525. $group['attribs']['name'] . '"', $params);
  526. if (is_array($ret)) {
  527. $this->_downloadDeps[] = $ret;
  528. } elseif (PEAR::isError($ret) && !isset($options['soft'])) {
  529. $this->_downloader->log(0, $ret->getMessage());
  530. }
  531. }
  532. } else {
  533. $ret = $this->_detect2Dep($group[$packagetype], $pname,
  534. 'dependency group "' .
  535. $group['attribs']['name'] . '"', $params);
  536. if (is_array($ret)) {
  537. $this->_downloadDeps[] = $ret;
  538. } elseif (PEAR::isError($ret) && !isset($options['soft'])) {
  539. $this->_downloader->log(0, $ret->getMessage());
  540. }
  541. }
  542. }
  543. }
  544. }
  545. function _detect2Dep($dep, $pname, $group, $params)
  546. {
  547. if (isset($dep['conflicts'])) {
  548. return true;
  549. }
  550. $options = $this->_downloader->getOptions();
  551. if (isset($dep['uri'])) {
  552. return array('uri' => $dep['uri'], 'dep' => $dep);;
  553. }
  554. $testdep = $dep;
  555. $testdep['package'] = $dep['name'];
  556. if (PEAR_Downloader_Package::willDownload($testdep, $params)) {
  557. $dep['package'] = $dep['name'];
  558. if (!isset($options['soft'])) {
  559. $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group .
  560. ' dependency "' .
  561. $this->_registry->parsedPackageNameToString($dep, true) .
  562. '", will be installed');
  563. }
  564. return false;
  565. }
  566. $options = $this->_downloader->getOptions();
  567. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  568. if ($this->_explicitState) {
  569. $pname['state'] = $this->_explicitState;
  570. }
  571. $url = $this->_downloader->_getDepPackageDownloadUrl($dep, $pname);
  572. if (PEAR::isError($url)) {
  573. PEAR::popErrorHandling();
  574. return $url;
  575. }
  576. $dep['package'] = $dep['name'];
  577. $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params, $group == 'optional' &&
  578. !isset($options['alldeps']), true);
  579. PEAR::popErrorHandling();
  580. if (PEAR::isError($ret)) {
  581. if (!isset($options['soft'])) {
  582. $this->_downloader->log(0, $ret->getMessage());
  583. }
  584. return false;
  585. }
  586. // check to see if a dep is already installed and is the same or newer
  587. if (!isset($dep['min']) && !isset($dep['max']) && !isset($dep['recommended'])) {
  588. $oper = 'has';
  589. } else {
  590. $oper = 'gt';
  591. }
  592. // do not try to move this before getDepPackageDownloadURL
  593. // we can't determine whether upgrade is necessary until we know what
  594. // version would be downloaded
  595. if (!isset($options['force']) && $this->isInstalled($ret, $oper)) {
  596. $version = $this->_installRegistry->packageInfo($dep['name'], 'version', $dep['channel']);
  597. $dep['package'] = $dep['name'];
  598. if (!isset($options['soft'])) {
  599. $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group .
  600. ' dependency "' .
  601. $this->_registry->parsedPackageNameToString($dep, true) .
  602. '" version ' . $url['version'] . ', already installed as version ' .
  603. $version);
  604. }
  605. return false;
  606. }
  607. if (isset($dep['nodefault'])) {
  608. $ret['nodefault'] = true;
  609. }
  610. return $ret;
  611. }
  612. function _detect1($deps, $pname, $options, $params)
  613. {
  614. $this->_downloadDeps = array();
  615. $skipnames = array();
  616. foreach ($deps as $dep) {
  617. $nodownload = false;
  618. if (isset ($dep['type']) && $dep['type'] === 'pkg') {
  619. $dep['channel'] = 'pear.php.net';
  620. $dep['package'] = $dep['name'];
  621. switch ($dep['rel']) {
  622. case 'not' :
  623. continue 2;
  624. case 'ge' :
  625. case 'eq' :
  626. case 'gt' :
  627. case 'has' :
  628. $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
  629. 'required' :
  630. 'optional';
  631. if (PEAR_Downloader_Package::willDownload($dep, $params)) {
  632. $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group
  633. . ' dependency "' .
  634. $this->_registry->parsedPackageNameToString($dep, true) .
  635. '", will be installed');
  636. continue 2;
  637. }
  638. $fakedp = new PEAR_PackageFile_v1;
  639. $fakedp->setPackage($dep['name']);
  640. // skip internet check if we are not upgrading (bug #5810)
  641. if (!isset($options['upgrade']) && $this->isInstalled(
  642. $fakedp, $dep['rel'])) {
  643. $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group
  644. . ' dependency "' .
  645. $this->_registry->parsedPackageNameToString($dep, true) .
  646. '", is already installed');
  647. continue 2;
  648. }
  649. }
  650. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  651. if ($this->_explicitState) {
  652. $pname['state'] = $this->_explicitState;
  653. }
  654. $url = $this->_downloader->_getDepPackageDownloadUrl($dep, $pname);
  655. $chan = 'pear.php.net';
  656. if (PEAR::isError($url)) {
  657. // check to see if this is a pecl package that has jumped
  658. // from pear.php.net to pecl.php.net channel
  659. if (!class_exists('PEAR_Dependency2')) {
  660. require_once 'PEAR/Dependency2.php';
  661. }
  662. $newdep = PEAR_Dependency2::normalizeDep($dep);
  663. $newdep = $newdep[0];
  664. $newdep['channel'] = 'pecl.php.net';
  665. $chan = 'pecl.php.net';
  666. $url = $this->_downloader->_getDepPackageDownloadUrl($newdep, $pname);
  667. $obj = &$this->_installRegistry->getPackage($dep['name']);
  668. if (PEAR::isError($url)) {
  669. PEAR::popErrorHandling();
  670. if ($obj !== null && $this->isInstalled($obj, $dep['rel'])) {
  671. $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
  672. 'required' :
  673. 'optional';
  674. $dep['package'] = $dep['name'];
  675. if (!isset($options['soft'])) {
  676. $this->_downloader->log(3, $this->getShortName() .
  677. ': Skipping ' . $group . ' dependency "' .
  678. $this->_registry->parsedPackageNameToString($dep, true) .
  679. '", already installed as version ' . $obj->getVersion());
  680. }
  681. $skip = count($skipnames) ?
  682. $skipnames[count($skipnames) - 1] : '';
  683. if ($skip ==
  684. $this->_registry->parsedPackageNameToString($dep, true)) {
  685. array_pop($skipnames);
  686. }
  687. continue;
  688. } else {
  689. if (isset($dep['optional']) && $dep['optional'] == 'yes') {
  690. $this->_downloader->log(2, $this->getShortName() .
  691. ': Skipping optional dependency "' .
  692. $this->_registry->parsedPackageNameToString($dep, true) .
  693. '", no releases exist');
  694. continue;
  695. } else {
  696. return $url;
  697. }
  698. }
  699. }
  700. }
  701. PEAR::popErrorHandling();
  702. if (!isset($options['alldeps'])) {
  703. if (isset($dep['optional']) && $dep['optional'] == 'yes') {
  704. if (!isset($options['soft'])) {
  705. $this->_downloader->log(3, 'Notice: package "' .
  706. $this->getShortName() .
  707. '" optional dependency "' .
  708. $this->_registry->parsedPackageNameToString(
  709. array('channel' => $chan, 'package' =>
  710. $dep['name']), true) .
  711. '" will not be automatically downloaded');
  712. }
  713. $skipnames[] = $this->_registry->parsedPackageNameToString(
  714. array('channel' => $chan, 'package' =>
  715. $dep['name']), true);
  716. $nodownload = true;
  717. }
  718. }
  719. if (!isset($options['alldeps']) && !isset($options['onlyreqdeps'])) {
  720. if (!isset($dep['optional']) || $dep['optional'] == 'no') {
  721. if (!isset($options['soft'])) {
  722. $this->_downloader->log(3, 'Notice: package "' .
  723. $this->getShortName() .
  724. '" required dependency "' .
  725. $this->_registry->parsedPackageNameToString(
  726. array('channel' => $chan, 'package' =>
  727. $dep['name']), true) .
  728. '" will not be automatically downloaded');
  729. }
  730. $skipnames[] = $this->_registry->parsedPackageNameToString(
  731. array('channel' => $chan, 'package' =>
  732. $dep['name']), true);
  733. $nodownload = true;
  734. }
  735. }
  736. // check to see if a dep is already installed
  737. // do not try to move this before getDepPackageDownloadURL
  738. // we can't determine whether upgrade is necessary until we know what
  739. // version would be downloaded
  740. if (!isset($options['force']) && $this->isInstalled(
  741. $url, $dep['rel'])) {
  742. $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
  743. 'required' :
  744. 'optional';
  745. $dep['package'] = $dep['name'];
  746. if (isset($newdep)) {
  747. $version = $this->_installRegistry->packageInfo($newdep['name'], 'version', $newdep['channel']);
  748. } else {
  749. $version = $this->_installRegistry->packageInfo($dep['name'], 'version');
  750. }
  751. $dep['version'] = $url['version'];
  752. if (!isset($options['soft'])) {
  753. $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group .
  754. ' dependency "' .
  755. $this->_registry->parsedPackageNameToString($dep, true) .
  756. '", already installed as version ' . $version);
  757. }
  758. $skip = count($skipnames) ?
  759. $skipnames[count($skipnames) - 1] : '';
  760. if ($skip ==
  761. $this->_registry->parsedPackageNameToString($dep, true)) {
  762. array_pop($skipnames);
  763. }
  764. continue;
  765. }
  766. if ($nodownload) {
  767. continue;
  768. }
  769. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  770. if (isset($newdep)) {
  771. $dep = $newdep;
  772. }
  773. $dep['package'] = $dep['name'];
  774. $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params,
  775. isset($dep['optional']) && $dep['optional'] == 'yes' &&
  776. !isset($options['alldeps']), true);
  777. PEAR::popErrorHandling();
  778. if (PEAR::isError($ret)) {
  779. if (!isset($options['soft'])) {
  780. $this->_downloader->log(0, $ret->getMessage());
  781. }
  782. continue;
  783. }
  784. $this->_downloadDeps[] = $ret;
  785. }
  786. }
  787. if (count($skipnames)) {
  788. if (!isset($options['soft'])) {
  789. $this->_downloader->log(1, 'Did not download dependencies: ' .
  790. implode(', ', $skipnames) .
  791. ', use --alldeps or --onlyreqdeps to download automatically');
  792. }
  793. }
  794. }
  795. function setDownloadURL($pkg)
  796. {
  797. $this->_downloadURL = $pkg;
  798. }
  799. /**
  800. * Set the package.xml object for this downloaded package
  801. *
  802. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 $pkg
  803. */
  804. function setPackageFile(&$pkg)
  805. {
  806. $this->_packagefile = &$pkg;
  807. }
  808. function getShortName()
  809. {
  810. return $this->_registry->parsedPackageNameToString(array('channel' => $this->getChannel(),
  811. 'package' => $this->getPackage()), true);
  812. }
  813. function getParsedPackage()
  814. {
  815. if (isset($this->_packagefile) || isset($this->_parsedname)) {
  816. return array('channel' => $this->getChannel(),
  817. 'package' => $this->getPackage(),
  818. 'version' => $this->getVersion());
  819. }
  820. return false;
  821. }
  822. function getDownloadURL()
  823. {
  824. return $this->_downloadURL;
  825. }
  826. function canDefault()
  827. {
  828. if (isset($this->_downloadURL) && isset($this->_downloadURL['nodefault'])) {
  829. return false;
  830. }
  831. return true;
  832. }
  833. function getPackage()
  834. {
  835. if (isset($this->_packagefile)) {
  836. return $this->_packagefile->getPackage();
  837. } elseif (isset($this->_downloadURL['info'])) {
  838. return $this->_downloadURL['info']->getPackage();
  839. }
  840. return false;
  841. }
  842. /**
  843. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  844. */
  845. function isSubpackage(&$pf)
  846. {
  847. if (isset($this->_packagefile)) {
  848. return $this->_packagefile->isSubpackage($pf);
  849. } elseif (isset($this->_downloadURL['info'])) {
  850. return $this->_downloadURL['info']->isSubpackage($pf);
  851. }
  852. return false;
  853. }
  854. function getPackageType()
  855. {
  856. if (isset($this->_packagefile)) {
  857. return $this->_packagefile->getPackageType();
  858. } elseif (isset($this->_downloadURL['info'])) {
  859. return $this->_downloadURL['info']->getPackageType();
  860. }
  861. return false;
  862. }
  863. function isBundle()
  864. {
  865. if (isset($this->_packagefile)) {
  866. return $this->_packagefile->getPackageType() == 'bundle';
  867. }
  868. return false;
  869. }
  870. function getPackageXmlVersion()
  871. {
  872. if (isset($this->_packagefile)) {
  873. return $this->_packagefile->getPackagexmlVersion();
  874. } elseif (isset($this->_downloadURL['info'])) {
  875. return $this->_downloadURL['info']->getPackagexmlVersion();
  876. }
  877. return '1.0';
  878. }
  879. function getChannel()
  880. {
  881. if (isset($this->_packagefile)) {
  882. return $this->_packagefile->getChannel();
  883. } elseif (isset($this->_downloadURL['info'])) {
  884. return $this->_downloadURL['info']->getChannel();
  885. }
  886. return false;
  887. }
  888. function getURI()
  889. {
  890. if (isset($this->_packagefile)) {
  891. return $this->_packagefile->getURI();
  892. } elseif (isset($this->_downloadURL['info'])) {
  893. return $this->_downloadURL['info']->getURI();
  894. }
  895. return false;
  896. }
  897. function getVersion()
  898. {
  899. if (isset($this->_packagefile)) {
  900. return $this->_packagefile->getVersion();
  901. } elseif (isset($this->_downloadURL['version'])) {
  902. return $this->_downloadURL['version'];
  903. }
  904. return false;
  905. }
  906. function isCompatible($pf)
  907. {
  908. if (isset($this->_packagefile)) {
  909. return $this->_packagefile->isCompatible($pf);
  910. } elseif (isset($this->_downloadURL['info'])) {
  911. return $this->_downloadURL['info']->isCompatible($pf);
  912. }
  913. return true;
  914. }
  915. function setGroup($group)
  916. {
  917. $this->_parsedname['group'] = $group;
  918. }
  919. function getGroup()
  920. {
  921. if (isset($this->_parsedname['group'])) {
  922. return $this->_parsedname['group'];
  923. }
  924. return '';
  925. }
  926. function isExtension($name)
  927. {
  928. if (isset($this->_packagefile)) {
  929. return $this->_packagefile->isExtension($name);
  930. } elseif (isset($this->_downloadURL['info'])) {
  931. if ($this->_downloadURL['info']->getPackagexmlVersion() == '2.0') {
  932. return $this->_downloadURL['info']->getProvidesExtension() == $name;
  933. }
  934. return false;
  935. }
  936. return false;
  937. }
  938. function getDeps()
  939. {
  940. if (isset($this->_packagefile)) {
  941. $ver = $this->_packagefile->getPackagexmlVersion();
  942. if (version_compare($ver, '2.0', '>=')) {
  943. return $this->_packagefile->getDeps(true);
  944. }
  945. return $this->_packagefile->getDeps();
  946. } elseif (isset($this->_downloadURL['info'])) {
  947. $ver = $this->_downloadURL['info']->getPackagexmlVersion();
  948. if (version_compare($ver, '2.0', '>=')) {
  949. return $this->_downloadURL['info']->getDeps(true);
  950. }
  951. return $this->_downloadURL['info']->getDeps();
  952. }
  953. return array();
  954. }
  955. /**
  956. * @param array Parsed array from {@link PEAR_Registry::parsePackageName()} or a dependency
  957. * returned from getDepDownloadURL()
  958. */
  959. function isEqual($param)
  960. {
  961. if (is_object($param)) {
  962. $channel = $param->getChannel();
  963. $package = $param->getPackage();
  964. if ($param->getURI()) {
  965. $param = array(
  966. 'channel' => $param->getChannel(),
  967. 'package' => $param->getPackage(),
  968. 'version' => $param->getVersion(),
  969. 'uri' => $param->getURI(),
  970. );
  971. } else {
  972. $param = array(
  973. 'channel' => $param->getChannel(),
  974. 'package' => $param->getPackage(),
  975. 'version' => $param->getVersion(),
  976. );
  977. }
  978. } else {
  979. if (isset($param['uri'])) {
  980. if ($this->getChannel() != '__uri') {
  981. return false;
  982. }
  983. return $param['uri'] == $this->getURI();
  984. }
  985. $package = isset($param['package']) ? $param['package'] : $param['info']->getPackage();
  986. $channel = isset($param['channel']) ? $param['channel'] : $param['info']->getChannel();
  987. if (isset($param['rel'])) {
  988. if (!class_exists('PEAR_Dependency2')) {
  989. require_once 'PEAR/Dependency2.php';
  990. }
  991. $newdep = PEAR_Dependency2::normalizeDep($param);
  992. $newdep = $newdep[0];
  993. } elseif (isset($param['min'])) {
  994. $newdep = $param;
  995. }
  996. }
  997. if (isset($newdep)) {
  998. if (!isset($newdep['min'])) {
  999. $newdep['min'] = '0';
  1000. }
  1001. if (!isset($newdep['max'])) {
  1002. $newdep['max'] = '100000000000000000000';
  1003. }
  1004. // use magic to support pecl packages suddenly jumping to the pecl channel
  1005. // we need to support both dependency possibilities
  1006. if ($channel == 'pear.php.net' && $this->getChannel() == 'pecl.php.net') {
  1007. if ($package == $this->getPackage()) {
  1008. $channel = 'pecl.php.net';
  1009. }
  1010. }
  1011. if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') {
  1012. if ($package == $this->getPackage()) {
  1013. $channel = 'pear.php.net';
  1014. }
  1015. }
  1016. return (strtolower($package) == strtolower($this->getPackage()) &&
  1017. $channel == $this->getChannel() &&
  1018. version_compare($newdep['min'], $this->getVersion(), '<=') &&
  1019. version_compare($newdep['max'], $this->getVersion(), '>='));
  1020. }
  1021. // use magic to support pecl packages suddenly jumping to the pecl channel
  1022. if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') {
  1023. if (strtolower($package) == strtolower($this->getPackage())) {
  1024. $channel = 'pear.php.net';
  1025. }
  1026. }
  1027. if (isset($param['version'])) {
  1028. return (strtolower($package) == strtolower($this->getPackage()) &&
  1029. $channel == $this->getChannel() &&
  1030. $param['version'] == $this->getVersion());
  1031. }
  1032. return strtolower($package) == strtolower($this->getPackage()) &&
  1033. $channel == $this->getChannel();
  1034. }
  1035. function isInstalled($dep, $oper = '==')
  1036. {
  1037. if (!$dep) {
  1038. return false;
  1039. }
  1040. if ($oper != 'ge' && $oper != 'gt' && $oper != 'has' && $oper != '==') {
  1041. return false;
  1042. }
  1043. if (is_object($dep)) {
  1044. $package = $dep->getPackage();
  1045. $channel = $dep->getChannel();
  1046. if ($dep->getURI()) {
  1047. $dep = array(
  1048. 'uri' => $dep->getURI(),
  1049. 'version' => $dep->getVersion(),
  1050. );
  1051. } else {
  1052. $dep = array(
  1053. 'version' => $dep->getVersion(),
  1054. );
  1055. }
  1056. } else {
  1057. if (isset($dep['uri'])) {
  1058. $channel = '__uri';
  1059. $package = $dep['dep']['name'];
  1060. } else {
  1061. $channel = $dep['info']->getChannel();
  1062. $package = $dep['info']->getPackage();
  1063. }
  1064. }
  1065. $options = $this->_downloader->getOptions();
  1066. $test = $this->_installRegistry->packageExists($package, $channel);
  1067. if (!$test && $channel == 'pecl.php.net') {
  1068. // do magic to allow upgrading from old pecl packages to new ones
  1069. $test = $this->_installRegistry->packageExists($package, 'pear.php.net');
  1070. $channel = 'pear.php.net';
  1071. }
  1072. if ($test) {
  1073. if (isset($dep['uri'])) {
  1074. if ($this->_installRegistry->packageInfo($package, 'uri', '__uri') == $dep['uri']) {
  1075. return true;
  1076. }
  1077. }
  1078. if (isset($options['upgrade'])) {
  1079. $packageVersion = $this->_installRegistry->packageInfo($package, 'version', $channel);
  1080. if (version_compare($packageVersion, $dep['version'], '>=')) {
  1081. return true;
  1082. }
  1083. return false;
  1084. }
  1085. return true;
  1086. }
  1087. return false;
  1088. }
  1089. /**
  1090. * Detect duplicate package names with differing versions
  1091. *
  1092. * If a user requests to install Date 1.4.6 and Date 1.4.7,
  1093. * for instance, this is a logic error. This method
  1094. * detects this situation.
  1095. *
  1096. * @param array $params array of PEAR_Downloader_Package objects
  1097. * @param array $errorparams empty array
  1098. * @return array array of stupid duplicated packages in PEAR_Downloader_Package obejcts
  1099. */
  1100. public static function detectStupidDuplicates($params, &$errorparams)
  1101. {
  1102. $existing = array();
  1103. foreach ($params as $i => $param) {
  1104. $package = $param->getPackage();
  1105. $channel = $param->getChannel();
  1106. $group = $param->getGroup();
  1107. if (!isset($existing[$channel . '/' . $package])) {
  1108. $existing[$channel . '/' . $package] = array();
  1109. }
  1110. if (!isset($existing[$channel . '/' . $package][$group])) {
  1111. $existing[$channel . '/' . $package][$group] = array();
  1112. }
  1113. $existing[$channel . '/' . $package][$group][] = $i;
  1114. }
  1115. $indices = array();
  1116. foreach ($existing as $package => $groups) {
  1117. foreach ($groups as $group => $dupes) {
  1118. if (count($dupes) > 1) {
  1119. $indices = $indices + $dupes;
  1120. }
  1121. }
  1122. }
  1123. $indices = array_unique($indices);
  1124. foreach ($indices as $index) {
  1125. $errorparams[] = $params[$index];
  1126. }
  1127. return count($errorparams);
  1128. }
  1129. /**
  1130. * @param array
  1131. * @param bool ignore install groups - for final removal of dupe packages
  1132. */
  1133. public static function removeDuplicates(&$params, $ignoreGroups = false)
  1134. {
  1135. $pnames = array();
  1136. foreach ($params as $i => $param) {
  1137. if (!$param) {
  1138. continue;
  1139. }
  1140. if ($param->getPackage()) {
  1141. $group = $ignoreGroups ? '' : $param->getGroup();
  1142. $pnames[$i] = $param->getChannel() . '/' .
  1143. $param->getPackage() . '-' . $param->getVersion() . '#' . $group;
  1144. }
  1145. }
  1146. $pnames = array_unique($pnames);
  1147. $unset = array_diff(array_keys($params), array_keys($pnames));
  1148. $testp = array_flip($pnames);
  1149. foreach ($params as $i => $param) {
  1150. if (!$param) {
  1151. $unset[] = $i;
  1152. continue;
  1153. }
  1154. if (!is_a($param, 'PEAR_Downloader_Package')) {
  1155. $unset[] = $i;
  1156. continue;
  1157. }
  1158. $group = $ignoreGroups ? '' : $param->getGroup();
  1159. if (!isset($testp[$param->getChannel() . '/' . $param->getPackage() . '-' .
  1160. $param->getVersion() . '#' . $group])) {
  1161. $unset[] = $i;
  1162. }
  1163. }
  1164. foreach ($unset as $i) {
  1165. unset($params[$i]);
  1166. }
  1167. $ret = array();
  1168. foreach ($params as $i => $param) {
  1169. $ret[] = &$params[$i];
  1170. }
  1171. $params = array();
  1172. foreach ($ret as $i => $param) {
  1173. $params[] = &$ret[$i];
  1174. }
  1175. }
  1176. function explicitState()
  1177. {
  1178. return $this->_explicitState;
  1179. }
  1180. function setExplicitState($s)
  1181. {
  1182. $this->_explicitState = $s;
  1183. }
  1184. /**
  1185. */
  1186. public static function mergeDependencies(&$params)
  1187. {
  1188. $bundles = $newparams = array();
  1189. foreach ($params as $i => $param) {
  1190. if (!$param->isBundle()) {
  1191. continue;
  1192. }
  1193. $bundles[] = $i;
  1194. $pf = &$param->getPackageFile();
  1195. $newdeps = array();
  1196. $contents = $pf->getBundledPackages();
  1197. if (!is_array($contents)) {
  1198. $contents = array($contents);
  1199. }
  1200. foreach ($contents as $file) {
  1201. $filecontents = $pf->getFileContents($file);
  1202. $dl = &$param->getDownloader();
  1203. $options = $dl->getOptions();
  1204. if (PEAR::isError($dir = $dl->getDownloadDir())) {
  1205. return $dir;
  1206. }
  1207. $fp = @fopen($dir . DIRECTORY_SEPARATOR . $file, 'wb');
  1208. if (!$fp) {
  1209. continue;
  1210. }
  1211. // FIXME do symlink check
  1212. fwrite($fp, $filecontents, strlen($filecontents));
  1213. fclose($fp);
  1214. if ($s = $params[$i]->explicitState()) {
  1215. $obj->setExplicitState($s);
  1216. }
  1217. $obj = new PEAR_Downloader_Package($params[$i]->getDownloader());
  1218. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  1219. if (PEAR::isError($dir = $dl->getDownloadDir())) {
  1220. PEAR::popErrorHandling();
  1221. return $dir;
  1222. }
  1223. $a = $dir . DIRECTORY_SEPARATOR . $file;
  1224. $e = $obj->_fromFile($a);
  1225. PEAR::popErrorHandling();
  1226. if (PEAR::isError($e)) {
  1227. if (!isset($options['soft'])) {
  1228. $dl->log(0, $e->getMessage());
  1229. }
  1230. continue;
  1231. }
  1232. if (!PEAR_Downloader_Package::willDownload($obj,
  1233. array_merge($params, $newparams)) && !$param->isInstalled($obj)) {
  1234. $newparams[] = $obj;
  1235. }
  1236. }
  1237. }
  1238. foreach ($bundles as $i) {
  1239. unset($params[$i]); // remove bundles - only their contents matter for installation
  1240. }
  1241. PEAR_Downloader_Package::removeDuplicates($params); // strip any unset indices
  1242. if (count($newparams)) { // add in bundled packages for install
  1243. foreach ($newparams as $i => $unused) {
  1244. $params[] = &$newparams[$i];
  1245. }
  1246. $newparams = array();
  1247. }
  1248. foreach ($params as $i => $param) {
  1249. $newdeps = array();
  1250. foreach ($param->_downloadDeps as $dep) {
  1251. $merge = array_merge($params, $newparams);
  1252. if (!PEAR_Downloader_Package::willDownload($dep, $merge)
  1253. && !$param->isInstalled($dep)
  1254. ) {
  1255. $newdeps[] = $dep;
  1256. } else {
  1257. //var_dump($dep);
  1258. // detect versioning conflicts here
  1259. }
  1260. }
  1261. // convert the dependencies into PEAR_Downloader_Package objects for the next time around
  1262. $params[$i]->_downloadDeps = array();
  1263. foreach ($newdeps as $dep) {
  1264. $obj = new PEAR_Downloader_Package($params[$i]->getDownloader());
  1265. if ($s = $params[$i]->explicitState()) {
  1266. $obj->setExplicitState($s);
  1267. }
  1268. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  1269. $e = $obj->fromDepURL($dep);
  1270. PEAR::popErrorHandling();
  1271. if (PEAR::isError($e)) {
  1272. if (!isset($options['soft'])) {
  1273. $obj->_downloader->log(0, $e->getMessage());
  1274. }
  1275. continue;
  1276. }
  1277. $e = $obj->detectDependencies($params);
  1278. if (PEAR::isError($e)) {
  1279. if (!isset($options['soft'])) {
  1280. $obj->_downloader->log(0, $e->getMessage());
  1281. }
  1282. }
  1283. $newparams[] = $obj;
  1284. }
  1285. }
  1286. if (count($newparams)) {
  1287. foreach ($newparams as $i => $unused) {
  1288. $params[] = &$newparams[$i];
  1289. }
  1290. return true;
  1291. }
  1292. return false;
  1293. }
  1294. /**
  1295. */
  1296. public static function willDownload($param, $params)
  1297. {
  1298. if (!is_array($params)) {
  1299. return false;
  1300. }
  1301. foreach ($params as $obj) {
  1302. if ($obj->isEqual($param)) {
  1303. return true;
  1304. }
  1305. }
  1306. return false;
  1307. }
  1308. /**
  1309. * For simpler unit-testing
  1310. * @param PEAR_Config
  1311. * @param int
  1312. * @param string
  1313. */
  1314. function &getPackagefileObject(&$c, $d)
  1315. {
  1316. $a = new PEAR_PackageFile($c, $d);
  1317. return $a;
  1318. }
  1319. /**
  1320. * This will retrieve from a local file if possible, and parse out
  1321. * a group name as well. The original parameter will be modified to reflect this.
  1322. * @param string|array can be a parsed package name as well
  1323. * @access private
  1324. */
  1325. function _fromFile(&$param)
  1326. {
  1327. $saveparam = $param;
  1328. if (is_string($param) && substr($param, 0, 10) !== 'channel://') {
  1329. if (!@file_exists($param)) {
  1330. $test = explode('#', $param);
  1331. $group = array_pop($test);
  1332. if (@file_exists(implode('#', $test))) {
  1333. $this->setGroup($group);
  1334. $param = implode('#', $test);
  1335. $this->_explicitGroup = true;
  1336. }
  1337. }
  1338. if (@is_file($param)) {
  1339. $this->_type = 'local';
  1340. $options = $this->_downloader->getOptions();
  1341. $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->_debug);
  1342. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  1343. $pf = &$pkg->fromAnyFile($param, PEAR_VALIDATE_INSTALLING);
  1344. PEAR::popErrorHandling();
  1345. if (PEAR::isError($pf)) {
  1346. $this->_valid = false;
  1347. $param = $saveparam;
  1348. return $pf;
  1349. }
  1350. $this->_packagefile = &$pf;
  1351. if (!$this->getGroup()) {
  1352. $this->setGroup('default'); // install the default dependency group
  1353. }
  1354. return $this->_valid = true;
  1355. }
  1356. }
  1357. $param = $saveparam;
  1358. return $this->_valid = false;
  1359. }
  1360. function _fromUrl($param, $saveparam = '')
  1361. {
  1362. if (!is_array($param) && (preg_match('#^(http|https|ftp)://#', $param))) {
  1363. $options = $this->_downloader->getOptions();
  1364. $this->_type = 'url';
  1365. $callback = $this->_downloader->ui ?
  1366. array(&$this->_downloader, '_downloadCallback') : null;
  1367. $this->_downloader->pushErrorHandling(PEAR_ERROR_RETURN);
  1368. if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) {
  1369. $this->_downloader->popErrorHandling();
  1370. return $dir;
  1371. }
  1372. $this->_downloader->log(3, 'Downloading "' . $param . '"');
  1373. $file = $this->_downloader->downloadHttp($param, $this->_downloader->ui,
  1374. $dir, $callback, null, false, $this->getChannel());
  1375. $this->_downloader->popErrorHandling();
  1376. if (PEAR::isError($file)) {
  1377. if (!empty($saveparam)) {
  1378. $saveparam = ", cannot download \"$saveparam\"";
  1379. }
  1380. $err = PEAR::raiseError('Could not download from "' . $param .
  1381. '"' . $saveparam . ' (' . $file->getMessage() . ')');
  1382. return $err;
  1383. }
  1384. if ($this->_rawpackagefile) {
  1385. require_once 'Archive/Tar.php';
  1386. $tar = new Archive_Tar($file);
  1387. $packagexml = $tar->extractInString('package2.xml');
  1388. if (!$packagexml) {
  1389. $packagexml = $tar->extractInString('package.xml');
  1390. }
  1391. if (str_replace(array("\n", "\r"), array('',''), $packagexml) !=
  1392. str_replace(array("\n", "\r"), array('',''), $this->_rawpackagefile)) {
  1393. if ($this->getChannel() != 'pear.php.net') {
  1394. return PEAR::raiseError('CRITICAL ERROR: package.xml downloaded does ' .
  1395. 'not match value returned from xml-rpc');
  1396. }
  1397. // be more lax for the existing PEAR packages that have not-ok
  1398. // characters in their package.xml
  1399. $this->_downloader->log(0, 'CRITICAL WARNING: The "' .
  1400. $this->getPackage() . '" package has invalid characters in its ' .
  1401. 'package.xml. The next version of PEAR may not be able to install ' .
  1402. 'this package for security reasons. Please open a bug report at ' .
  1403. 'http://pear.php.net/package/' . $this->getPackage() . '/bugs');
  1404. }
  1405. }
  1406. // whew, download worked!
  1407. $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug);
  1408. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  1409. $pf = &$pkg->fromAnyFile($file, PEAR_VALIDATE_INSTALLING);
  1410. PEAR::popErrorHandling();
  1411. if (PEAR::isError($pf)) {
  1412. if (is_array($pf->getUserInfo())) {
  1413. foreach ($pf->getUserInfo() as $err) {
  1414. if (is_array($err)) {
  1415. $err = $err['message'];
  1416. }
  1417. if (!isset($options['soft'])) {
  1418. $this->_downloader->log(0, "Validation Error: $err");
  1419. }
  1420. }
  1421. }
  1422. if (!isset($options['soft'])) {
  1423. $this->_downloader->log(0, $pf->getMessage());
  1424. }
  1425. ///FIXME need to pass back some error code that we can use to match with to cancel all further operations
  1426. /// At least stop all deps of this package from being installed
  1427. $out = $saveparam ? $saveparam : $param;
  1428. $err = PEAR::raiseError('Download of "' . $out . '" succeeded, but it is not a valid package archive');
  1429. $this->_valid = false;
  1430. return $err;
  1431. }
  1432. $this->_packagefile = &$pf;
  1433. $this->setGroup('default'); // install the default dependency group
  1434. return $this->_valid = true;
  1435. }
  1436. return $this->_valid = false;
  1437. }
  1438. /**
  1439. *
  1440. * @param string|array pass in an array of format
  1441. * array(
  1442. * 'package' => 'pname',
  1443. * ['channel' => 'channame',]
  1444. * ['version' => 'version',]
  1445. * ['state' => 'state',])
  1446. * or a string of format [channame/]pname[-version|-state]
  1447. */
  1448. function _fromString($param)
  1449. {
  1450. $options = $this->_downloader->getOptions();
  1451. $channel = $this->_config->get('default_channel');
  1452. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  1453. $pname = $this->_registry->parsePackageName($param, $channel);
  1454. PEAR::popErrorHandling();
  1455. if (PEAR::isError($pname)) {
  1456. if ($pname->getCode() == 'invalid') {
  1457. $this->_valid = false;
  1458. return false;
  1459. }
  1460. if ($pname->getCode() == 'channel') {
  1461. $parsed = $pname->getUserInfo();
  1462. if ($this->_downloader->discover($parsed['channel'])) {
  1463. if ($this->_config->get('auto_discover')) {
  1464. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  1465. $pname = $this->_registry->parsePackageName($param, $channel);
  1466. PEAR::popErrorHandling();
  1467. } else {
  1468. if (!isset($options['soft'])) {
  1469. $this->_downloader->log(0, 'Channel "' . $parsed['channel'] .
  1470. '" is not initialized, use ' .
  1471. '"pear channel-discover ' . $parsed['channel'] . '" to initialize' .
  1472. 'or pear config-set auto_discover 1');
  1473. }
  1474. }
  1475. }
  1476. if (PEAR::isError($pname)) {
  1477. if (!isset($options['soft'])) {
  1478. $this->_downloader->log(0, $pname->getMessage());
  1479. }
  1480. if (is_array($param)) {
  1481. $param = $this->_registry->parsedPackageNameToString($param);
  1482. }
  1483. $err = PEAR::raiseError('invalid package name/package file "' . $param . '"');
  1484. $this->_valid = false;
  1485. return $err;
  1486. }
  1487. } else {
  1488. if (!isset($options['soft'])) {
  1489. $this->_downloader->log(0, $pname->getMessage());
  1490. }
  1491. $err = PEAR::raiseError('invalid package name/package file "' . $param . '"');
  1492. $this->_valid = false;
  1493. return $err;
  1494. }
  1495. }
  1496. if (!isset($this->_type)) {
  1497. $this->_type = 'rest';
  1498. }
  1499. $this->_parsedname = $pname;
  1500. $this->_explicitState = isset($pname['state']) ? $pname['state'] : false;
  1501. $this->_explicitGroup = isset($pname['group']) ? true : false;
  1502. $info = $this->_downloader->_getPackageDownloadUrl($pname);
  1503. if (PEAR::isError($info)) {
  1504. if ($info->getCode() != -976 && $pname['channel'] == 'pear.php.net') {
  1505. // try pecl
  1506. $pname['channel'] = 'pecl.php.net';
  1507. if ($test = $this->_downloader->_getPackageDownloadUrl($pname)) {
  1508. if (!PEAR::isError($test)) {
  1509. $info = PEAR::raiseError($info->getMessage() . ' - package ' .
  1510. $this->_registry->parsedPackageNameToString($pname, true) .
  1511. ' can be installed with "pecl install ' . $pname['package'] .
  1512. '"');
  1513. } else {
  1514. $pname['channel'] = 'pear.php.net';
  1515. }
  1516. } else {
  1517. $pname['channel'] = 'pear.php.net';
  1518. }
  1519. }
  1520. return $info;
  1521. }
  1522. $this->_rawpackagefile = $info['raw'];
  1523. $ret = $this->_analyzeDownloadURL($info, $param, $pname);
  1524. if (PEAR::isError($ret)) {
  1525. return $ret;
  1526. }
  1527. if ($ret) {
  1528. $this->_downloadURL = $ret;
  1529. return $this->_valid = (bool) $ret;
  1530. }
  1531. }
  1532. /**
  1533. * @param array output of package.getDownloadURL
  1534. * @param string|array|object information for detecting packages to be downloaded, and
  1535. * for errors
  1536. * @param array name information of the package
  1537. * @param array|null packages to be downloaded
  1538. * @param bool is this an optional dependency?
  1539. * @param bool is this any kind of dependency?
  1540. * @access private
  1541. */
  1542. function _analyzeDownloadURL($info, $param, $pname, $params = null, $optional = false,
  1543. $isdependency = false)
  1544. {
  1545. if (!is_string($param) && PEAR_Downloader_Package::willDownload($param, $params)) {
  1546. return false;
  1547. }
  1548. if ($info === false) {
  1549. $saveparam = !is_string($param) ? ", cannot download \"$param\"" : '';
  1550. // no releases exist
  1551. return PEAR::raiseError('No releases for package "' .
  1552. $this->_registry->parsedPackageNameToString($pname, true) . '" exist' . $saveparam);
  1553. }
  1554. if (strtolower($info['info']->getChannel()) != strtolower($pname['channel'])) {
  1555. $err = false;
  1556. if ($pname['channel'] == 'pecl.php.net') {
  1557. if ($info['info']->getChannel() != 'pear.php.net') {
  1558. $err = true;
  1559. }
  1560. } elseif ($info['info']->getChannel() == 'pecl.php.net') {
  1561. if ($pname['channel'] != 'pear.php.net') {
  1562. $err = true;
  1563. }
  1564. } else {
  1565. $err = true;
  1566. }
  1567. if ($err) {
  1568. return PEAR::raiseError('SECURITY ERROR: package in channel "' . $pname['channel'] .
  1569. '" retrieved another channel\'s name for download! ("' .
  1570. $info['info']->getChannel() . '")');
  1571. }
  1572. }
  1573. $preferred_state = $this->_config->get('preferred_state');
  1574. if (!isset($info['url'])) {
  1575. $package_version = $this->_registry->packageInfo($info['info']->getPackage(),
  1576. 'version', $info['info']->getChannel());
  1577. if ($this->isInstalled($info)) {
  1578. if ($isdependency && version_compare($info['version'], $package_version, '<=')) {
  1579. // ignore bogus errors of "failed to download dependency"
  1580. // if it is already installed and the one that would be
  1581. // downloaded is older or the same version (Bug #7219)
  1582. return false;
  1583. }
  1584. }
  1585. if ($info['version'] === $package_version) {
  1586. if (!isset($options['soft'])) {
  1587. $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] .
  1588. '/' . $pname['package'] . '-' . $package_version. ', additionally the suggested version' .
  1589. ' (' . $package_version . ') is the same as the locally installed one.');
  1590. }
  1591. return false;
  1592. }
  1593. if (version_compare($info['version'], $package_version, '<=')) {
  1594. if (!isset($options['soft'])) {
  1595. $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] .
  1596. '/' . $pname['package'] . '-' . $package_version . ', additionally the suggested version' .
  1597. ' (' . $info['version'] . ') is a lower version than the locally installed one (' . $package_version . ').');
  1598. }
  1599. return false;
  1600. }
  1601. $instead = ', will instead download version ' . $info['version'] .
  1602. ', stability "' . $info['info']->getState() . '"';
  1603. // releases exist, but we failed to get any
  1604. if (isset($this->_downloader->_options['force'])) {
  1605. if (isset($pname['version'])) {
  1606. $vs = ', version "' . $pname['version'] . '"';
  1607. } elseif (isset($pname['state'])) {
  1608. $vs = ', stability "' . $pname['state'] . '"';
  1609. } elseif ($param == 'dependency') {
  1610. if (!class_exists('PEAR_Common')) {
  1611. require_once 'PEAR/Common.php';
  1612. }
  1613. if (!in_array($info['info']->getState(),
  1614. PEAR_Common::betterStates($preferred_state, true))) {
  1615. if ($optional) {
  1616. // don't spit out confusing error message
  1617. return $this->_downloader->_getPackageDownloadUrl(
  1618. array('package' => $pname['package'],
  1619. 'channel' => $pname['channel'],
  1620. 'version' => $info['version']));
  1621. }
  1622. $vs = ' within preferred state "' . $preferred_state .
  1623. '"';
  1624. } else {
  1625. if (!class_exists('PEAR_Dependency2')) {
  1626. require_once 'PEAR/Dependency2.php';
  1627. }
  1628. if ($optional) {
  1629. // don't spit out confusing error message
  1630. return $this->_downloader->_getPackageDownloadUrl(
  1631. array('package' => $pname['package'],
  1632. 'channel' => $pname['channel'],
  1633. 'version' => $info['version']));
  1634. }
  1635. $vs = PEAR_Dependency2::_getExtraString($pname);
  1636. $instead = '';
  1637. }
  1638. } else {
  1639. $vs = ' within preferred state "' . $preferred_state . '"';
  1640. }
  1641. if (!isset($options['soft'])) {
  1642. $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] .
  1643. '/' . $pname['package'] . $vs . $instead);
  1644. }
  1645. // download the latest release
  1646. return $this->_downloader->_getPackageDownloadUrl(
  1647. array('package' => $pname['package'],
  1648. 'channel' => $pname['channel'],
  1649. 'version' => $info['version']));
  1650. } else {
  1651. if (isset($info['php']) && $info['php']) {
  1652. $err = PEAR::raiseError('Failed to download ' .
  1653. $this->_registry->parsedPackageNameToString(
  1654. array('channel' => $pname['channel'],
  1655. 'package' => $pname['package']),
  1656. true) .
  1657. ', latest release is version ' . $info['php']['v'] .
  1658. ', but it requires PHP version "' .
  1659. $info['php']['m'] . '", use "' .
  1660. $this->_registry->parsedPackageNameToString(
  1661. array('channel' => $pname['channel'], 'package' => $pname['package'],
  1662. 'version' => $info['php']['v'])) . '" to install',
  1663. PEAR_DOWNLOADER_PACKAGE_PHPVERSION);
  1664. return $err;
  1665. }
  1666. // construct helpful error message
  1667. if (isset($pname['version'])) {
  1668. $vs = ', version "' . $pname['version'] . '"';
  1669. } elseif (isset($pname['state'])) {
  1670. $vs = ', stability "' . $pname['state'] . '"';
  1671. } elseif ($param == 'dependency') {
  1672. if (!class_exists('PEAR_Common')) {
  1673. require_once 'PEAR/Common.php';
  1674. }
  1675. if (!in_array($info['info']->getState(),
  1676. PEAR_Common::betterStates($preferred_state, true))) {
  1677. if ($optional) {
  1678. // don't spit out confusing error message, and don't die on
  1679. // optional dep failure!
  1680. return $this->_downloader->_getPackageDownloadUrl(
  1681. array('package' => $pname['package'],
  1682. 'channel' => $pname['channel'],
  1683. 'version' => $info['version']));
  1684. }
  1685. $vs = ' within preferred state "' . $preferred_state . '"';
  1686. } else {
  1687. if (!class_exists('PEAR_Dependency2')) {
  1688. require_once 'PEAR/Dependency2.php';
  1689. }
  1690. if ($optional) {
  1691. // don't spit out confusing error message, and don't die on
  1692. // optional dep failure!
  1693. return $this->_downloader->_getPackageDownloadUrl(
  1694. array('package' => $pname['package'],
  1695. 'channel' => $pname['channel'],
  1696. 'version' => $info['version']));
  1697. }
  1698. $vs = PEAR_Dependency2::_getExtraString($pname);
  1699. }
  1700. } else {
  1701. $vs = ' within preferred state "' . $this->_downloader->config->get('preferred_state') . '"';
  1702. }
  1703. $options = $this->_downloader->getOptions();
  1704. // this is only set by the "download-all" command
  1705. if (isset($options['ignorepreferred_state'])) {
  1706. $err = PEAR::raiseError(
  1707. 'Failed to download ' . $this->_registry->parsedPackageNameToString(
  1708. array('channel' => $pname['channel'], 'package' => $pname['package']),
  1709. true)
  1710. . $vs .
  1711. ', latest release is version ' . $info['version'] .
  1712. ', stability "' . $info['info']->getState() . '", use "' .
  1713. $this->_registry->parsedPackageNameToString(
  1714. array('channel' => $pname['channel'], 'package' => $pname['package'],
  1715. 'version' => $info['version'])) . '" to install',
  1716. PEAR_DOWNLOADER_PACKAGE_STATE);
  1717. return $err;
  1718. }
  1719. // Checks if the user has a package installed already and checks the release against
  1720. // the state against the installed package, this allows upgrades for packages
  1721. // with lower stability than the preferred_state
  1722. $stability = $this->_registry->packageInfo($pname['package'], 'stability', $pname['channel']);
  1723. if (!$this->isInstalled($info)
  1724. || !in_array($info['info']->getState(), PEAR_Common::betterStates($stability['release'], true))
  1725. ) {
  1726. $err = PEAR::raiseError(
  1727. 'Failed to download ' . $this->_registry->parsedPackageNameToString(
  1728. array('channel' => $pname['channel'], 'package' => $pname['package']),
  1729. true)
  1730. . $vs .
  1731. ', latest release is version ' . $info['version'] .
  1732. ', stability "' . $info['info']->getState() . '", use "' .
  1733. $this->_registry->parsedPackageNameToString(
  1734. array('channel' => $pname['channel'], 'package' => $pname['package'],
  1735. 'version' => $info['version'])) . '" to install');
  1736. return $err;
  1737. }
  1738. }
  1739. }
  1740. if (isset($info['deprecated']) && $info['deprecated']) {
  1741. $this->_downloader->log(0,
  1742. 'WARNING: "' .
  1743. $this->_registry->parsedPackageNameToString(
  1744. array('channel' => $info['info']->getChannel(),
  1745. 'package' => $info['info']->getPackage()), true) .
  1746. '" is deprecated in favor of "' .
  1747. $this->_registry->parsedPackageNameToString($info['deprecated'], true) .
  1748. '"');
  1749. }
  1750. return $info;
  1751. }
  1752. }