PageRenderTime 55ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/downloader/lib/Mage/Connect/Command/Install.php

https://bitbucket.org/andrewjleavitt/magestudy
PHP | 543 lines | 406 code | 60 blank | 77 comment | 108 complexity | 0eb382c3118905457edf0f7e55b7fb0f MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-2.1, GPL-2.0, WTFPL
  1. <?php
  2. /**
  3. * Magento
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@magentocommerce.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade Magento to newer
  18. * versions in the future. If you wish to customize Magento for your
  19. * needs please refer to http://www.magentocommerce.com for more information.
  20. *
  21. * @category Mage
  22. * @package Mage_Connect
  23. * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com)
  24. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  25. */
  26. final class Mage_Connect_Command_Install
  27. extends Mage_Connect_Command
  28. {
  29. /**
  30. * Install action callback
  31. * @param string $command
  32. * @param array $options
  33. * @param array $params
  34. * @return void
  35. */
  36. public function doInstall($command, $options, $params, $objects = array())
  37. {
  38. $this->cleanupParams($params);
  39. $installFileMode = $command === 'install-file';
  40. $cache=null;
  41. /**
  42. * @var $cache Mage_Connect_Singleconfig
  43. */
  44. $ftpObj=null;
  45. try {
  46. $packager = $this->getPackager();
  47. $forceMode = isset($options['force']);
  48. $upgradeAllMode = $command == 'upgrade-all';
  49. $upgradeMode = $command == 'upgrade' || $command == 'upgrade-all';
  50. $noFilesInstall = isset($options['nofiles']);
  51. $withDepsMode = !isset($options['nodeps']);
  52. $ignoreModifiedMode = true || !isset($options['ignorelocalmodification']);
  53. $clearInstallMode = $command == 'install' && !$forceMode;
  54. $installAll = isset($options['install_all']);
  55. $channelAuth = isset($options['auth'])?$options['auth']:array();
  56. $rest = $this->rest();
  57. $ftp = empty($options['ftp']) ? false : $options['ftp'];
  58. if($ftp) {
  59. list($cache, $config, $ftpObj) = $packager->getRemoteConf($ftp);
  60. } else {
  61. $config = $this->config();
  62. $cache = $this->getSconfig();
  63. }
  64. if(empty($config->magento_root)){
  65. $config->magento_root=dirname(dirname($_SERVER['SCRIPT_FILENAME']));
  66. }
  67. chdir($config->magento_root);
  68. $dirCache = DIRECTORY_SEPARATOR . $config->downloader_path . DIRECTORY_SEPARATOR . Mage_Connect_Config::DEFAULT_CACHE_PATH;
  69. $dirTmp = DIRECTORY_SEPARATOR . Mage_Connect_Package_Reader::PATH_TO_TEMPORARY_DIRECTORY;
  70. $dirMedia = DIRECTORY_SEPARATOR . 'media';
  71. $isWritable = true;
  72. if($ftp) {
  73. $cwd=$ftpObj->getcwd();
  74. $ftpObj->mkdirRecursive($cwd . $dirCache,0777);
  75. $ftpObj->chdir($cwd);
  76. $ftpObj->mkdirRecursive($cwd . $dirTmp,0777);
  77. $ftpObj->chdir($cwd);
  78. $ftpObj->mkdirRecursive($cwd . $dirMedia,0777);
  79. $ftpObj->chdir($cwd);
  80. $err = "Please check for sufficient ftp write file permissions.";
  81. } else {
  82. @mkdir($config->magento_root . $dirCache,0777,true);
  83. @mkdir($config->magento_root . $dirTmp,0777,true);
  84. @mkdir($config->magento_root . $dirMedia,0777,true);
  85. $isWritable = is_writable($config->magento_root)
  86. && is_writable($config->magento_root . DIRECTORY_SEPARATOR . $config->downloader_path)
  87. && is_writable($config->magento_root . $dirCache)
  88. && is_writable($config->magento_root . $dirTmp)
  89. && is_writable($config->magento_root . $dirMedia);
  90. $err = "Please check for sufficient write file permissions.";
  91. }
  92. $isWritable = $isWritable && is_writable($config->magento_root . $dirMedia)
  93. && is_writable($config->magento_root . $dirCache)
  94. && is_writable($config->magento_root . $dirTmp);
  95. if(!$isWritable){
  96. $this->doError($command, $err);
  97. throw new Exception('Your Magento folder does not have sufficient write permissions, which downloader requires.');
  98. }
  99. if(!empty($channelAuth)){
  100. $rest->getLoader()->setCredentials($channelAuth['username'], $channelAuth['password']);
  101. }
  102. if($installFileMode) {
  103. if(count($params) < 1) {
  104. throw new Exception("Argument should be: filename");
  105. }
  106. $filename = $params[0];
  107. if(!@file_exists($filename)) {
  108. throw new Exception("File '{$filename}' not found");
  109. }
  110. if(!@is_readable($filename)) {
  111. throw new Exception("File '{$filename}' is not readable");
  112. }
  113. $package = new Mage_Connect_Package($filename);
  114. $package->setConfig($config);
  115. $package->validate();
  116. $errors = $package->getErrors();
  117. if(count($errors)) {
  118. throw new Exception("Package file is invalid\n".implode("\n", $errors));
  119. }
  120. $pChan = $package->getChannel();
  121. $pName = $package->getName();
  122. $pVer = $package->getVersion();
  123. if (!($cache->isChannelName($pChan) || $cache->isChannelAlias($pChan))) {
  124. throw new Exception("The '{$pChan}' channel is not installed. Please use the MAGE shell script to install the '{$pChan}' channel.");
  125. }
  126. $conflicts = $cache->hasConflicts($pChan, $pName, $pVer);
  127. if(false !== $conflicts) {
  128. $conflicts = implode(", ",$conflicts);
  129. if($forceMode) {
  130. $this->doError($command, "Package {$pChan}/{$pName} {$pVer} conflicts with: ".$conflicts);
  131. } else {
  132. throw new Exception("Package {$pChan}/{$pName} {$pVer} conflicts with: ".$conflicts);
  133. }
  134. }
  135. $conflicts = $package->checkPhpDependencies();
  136. if(true !== $conflicts) {
  137. $confilcts = implode(",",$conflicts);
  138. $err = "Package {$pChan}/{$pName} {$pVer} depends on PHP extensions: ".$conflicts;
  139. if($forceMode) {
  140. $this->doError($command, $err);
  141. } else {
  142. throw new Exception($err);
  143. }
  144. }
  145. $conflicts = $package->checkPhpVersion();
  146. if(true !== $conflicts) {
  147. $err = "Package {$pChan}/{$pName} {$pVer}: ".$conflicts;
  148. if($forceMode) {
  149. $this->doError($command, $err);
  150. } else {
  151. throw new Exception($err);
  152. }
  153. }
  154. if(!$noFilesInstall) {
  155. if($ftp) {
  156. $packager->processInstallPackageFtp($package, $filename, $config, $ftpObj);
  157. } else {
  158. $packager->processInstallPackage($package, $filename, $config);
  159. }
  160. }
  161. $cache->addPackage($package);
  162. $installedDeps = array();
  163. $installedDepsAssoc = array();
  164. $installedDepsAssoc[] = array('channel'=>$pChan, 'name'=>$pName, 'version'=>$pVer);
  165. $installedDeps[] = array($pChan, $pName, $pVer);
  166. $title = isset($options['title']) ? $options['title'] : "Package installed: ";
  167. $out = array($command => array('data'=>$installedDeps, 'assoc'=>$installedDepsAssoc, 'title'=>$title));
  168. if($ftp) {
  169. $packager->writeToRemoteCache($cache, $ftpObj);
  170. @unlink($config->getFilename());
  171. }
  172. $this->ui()->output($out);
  173. return $out[$command]['data'];
  174. }
  175. if(!$upgradeAllMode) {
  176. if(count($params) < 2) {
  177. throw new Exception("Argument should be: channelName packageName");
  178. }
  179. $channel = $params[0];
  180. $package = $params[1];
  181. $argVersionMax = isset($params[2]) ? $params[2]: false;
  182. $argVersionMin = false;
  183. $cache->checkChannel($channel, $config, $rest);
  184. $channelName = $cache->chanName($channel);
  185. $this->ui()->output("Checking dependencies of packages");
  186. $packagesToInstall = $packager->getDependenciesList( $channelName, $package, $cache, $config, $argVersionMax, $argVersionMin, $withDepsMode, false, $rest);
  187. /*
  188. * @TODO: process 'failed' results
  189. */
  190. if(count($packagesToInstall['failed'])) {
  191. $showError=!count($packagesToInstall['result']);
  192. foreach($packagesToInstall['failed'] as $failed){
  193. //$failed = array('name'=>$package, 'channel'=>$chanName, 'max'=>$versionMax, 'min'=>$versionMin, 'reason'=>$e->getMessage());
  194. $msg="Package {$failed['channel']}/{$failed['name']} failed: ".$failed['reason'];
  195. if($showError){
  196. $this->doError($command, $msg);
  197. }else{
  198. $this->ui()->output($msg);
  199. }
  200. }
  201. }
  202. $packagesToInstall = $packagesToInstall['result'];
  203. } else {
  204. if(empty($params[0])) {
  205. $channels = $cache->getChannelNames();
  206. } else {
  207. $channel = $params[0];
  208. if(!$cache->isChannel($channel)) {
  209. throw new Exception("'{$channel}' is not existant channel name / valid uri");
  210. }
  211. $channels = $cache->chanName($channel);
  212. }
  213. $packagesToInstall = array();
  214. $neededToUpgrade = $packager->getUpgradesList($channels, $cache, $config, $rest);
  215. foreach($neededToUpgrade as $chan=>$packages) {
  216. foreach($packages as $name=>$data) {
  217. $versionTo = $data['to'];
  218. $tmp = $packager->getDependenciesList( $chan, $name, $cache, $config, $versionTo, $versionTo, $withDepsMode, false, $rest);
  219. if(count($tmp['result'])) {
  220. $packagesToInstall = array_merge($packagesToInstall, $tmp['result']);
  221. }
  222. }
  223. }
  224. }
  225. /**
  226. * Make installation
  227. */
  228. $installedDeps = array();
  229. $installedDepsAssoc = array();
  230. $keys = array();
  231. foreach($packagesToInstall as $package) {
  232. try {
  233. $pName = $package['name'];
  234. $pChan = $package['channel'];
  235. $pVer = $package['downloaded_version'];
  236. $pInstallState = $package['install_state'];
  237. $rest->setChannel($cache->chanUrl($pChan));
  238. /**
  239. * Skip existing packages
  240. */
  241. if ($upgradeMode && $cache->hasPackage($pChan, $pName, $pVer, $pVer) || ('already_installed' == $pInstallState && !$forceMode)) {
  242. $this->ui()->output("Already installed: {$pChan}/{$pName} {$pVer}, skipping");
  243. continue;
  244. }
  245. if('incompartible' == $pInstallState) {
  246. $this->ui()->output("Package incompartible with installed Magento: {$pChan}/{$pName} {$pVer}, skipping");
  247. continue;
  248. }
  249. $conflicts = $cache->hasConflicts($pChan, $pName, $pVer);
  250. if(false !== $conflicts) {
  251. $conflicts = implode(", ",$conflicts);
  252. if($forceMode) {
  253. $this->doError($command, "Package {$pChan}/{$pName} {$pVer} conflicts with: ".$conflicts);
  254. } else {
  255. throw new Exception("Package {$pChan}/{$pName} {$pVer} conflicts with: ".$conflicts);
  256. }
  257. }
  258. /**
  259. * Modifications
  260. */
  261. if (($upgradeMode || ($pInstallState == 'upgrade')) && !$ignoreModifiedMode) {
  262. if($ftp) {
  263. $modifications = $packager->getRemoteModifiedFiles($pChan, $pName, $cache, $config, $ftp);
  264. } else {
  265. $modifications = $packager->getLocalModifiedFiles($pChan, $pName, $cache, $config);
  266. }
  267. if (count($modifications) > 0) {
  268. $this->ui()->output('Changed locally: ');
  269. foreach ($modifications as $row) {
  270. if(!$ftp) {
  271. $this->ui()->output($config->magento_root.DS.$row);
  272. } else {
  273. $this->ui()->output($row);
  274. }
  275. }
  276. /*$this->ui()->confirm('Do you want rewrite all files?');
  277. continue;*/
  278. }
  279. }
  280. if($ftp) {
  281. $cwd=$ftpObj->getcwd();
  282. $dir=$cwd . DIRECTORY_SEPARATOR .$config->downloader_path . DIRECTORY_SEPARATOR . Mage_Connect_Config::DEFAULT_CACHE_PATH . DIRECTORY_SEPARATOR . trim( $pChan, "\\/");
  283. $ftpObj->mkdirRecursive($dir,0777);
  284. $ftpObj->chdir($cwd);
  285. } else {
  286. $dir = $config->getChannelCacheDir($pChan);
  287. @mkdir($dir, 0777, true);
  288. }
  289. $dir = $config->getChannelCacheDir($pChan);
  290. $packageFileName = $pName."-".$pVer.".tgz";
  291. $file = $dir.DIRECTORY_SEPARATOR.$packageFileName;
  292. if(!@file_exists($file)) {
  293. $this->ui()->output("Starting to download $packageFileName ...");
  294. $rest->downloadPackageFileOfRelease($pName, $pVer, $file);
  295. $this->ui()->output(sprintf("...done: %s bytes", number_format(filesize($file))));
  296. }
  297. /**
  298. * Remove old version package before install new
  299. */
  300. if ($cache->hasPackage($pChan, $pName)) {
  301. if ($ftp) {
  302. $packager->processUninstallPackageFtp($pChan, $pName, $cache, $ftpObj);
  303. } else {
  304. $packager->processUninstallPackage($pChan, $pName, $cache, $config);
  305. }
  306. $cache->deletePackage($pChan, $pName);
  307. }
  308. $package = new Mage_Connect_Package($file);
  309. if ($clearInstallMode && $pInstallState != 'upgrade' && !$installAll) {
  310. $this->validator()->validateContents($package->getContents(), $config);
  311. $errors = $this->validator()->getErrors();
  312. if (count($errors)) {
  313. throw new Exception("Package '{$pName}' is invalid\n" . implode("\n", $errors));
  314. }
  315. }
  316. $conflicts = $package->checkPhpDependencies();
  317. if(true !== $conflicts) {
  318. $confilcts = implode(",",$conflicts);
  319. $err = "Package {$pChan}/{$pName} {$pVer} depends on PHP extensions: ".$conflicts;
  320. if($forceMode) {
  321. $this->doError($command, $err);
  322. } else {
  323. throw new Exception($err);
  324. }
  325. }
  326. $conflicts = $package->checkPhpVersion();
  327. if(true !== $conflicts) {
  328. $err = "Package {$pChan}/{$pName} {$pVer}: ".$conflicts;
  329. if($forceMode) {
  330. $this->doError($command, $err);
  331. } else {
  332. throw new Exception($err);
  333. }
  334. }
  335. /**
  336. * @todo: make "Use custom permissions" functionality working
  337. */
  338. if(!$noFilesInstall) {
  339. $this->ui()->output("Installing package {$pChan}/{$pName} {$pVer}");
  340. if($ftp) {
  341. $packager->processInstallPackageFtp($package, $file, $config, $ftpObj);
  342. } else {
  343. $packager->processInstallPackage($package, $file, $config);
  344. }
  345. $this->ui()->output("Package {$pChan}/{$pName} {$pVer} installed successfully");
  346. }
  347. $cache->addPackage($package);
  348. $installedDepsAssoc[] = array('channel'=>$pChan, 'name'=>$pName, 'version'=>$pVer);
  349. $installedDeps[] = array($pChan, $pName, $pVer);
  350. } catch(Exception $e) {
  351. $this->doError($command, $e->getMessage());
  352. }
  353. }
  354. $title = isset($options['title']) ? $options['title'] : "Package installed: ";
  355. $out = array($command => array('data'=>$installedDeps, 'assoc'=>$installedDepsAssoc, 'title'=>$title));
  356. if($ftp) {
  357. $packager->writeToRemoteCache($cache, $ftpObj);
  358. @unlink($config->getFilename());
  359. }
  360. $this->ui()->output($out);
  361. return $out[$command]['data'];
  362. } catch (Exception $e) {
  363. if($ftp) {
  364. $packager->writeToRemoteCache($cache, $ftpObj);
  365. @unlink($config->getFilename());
  366. }
  367. return $this->doError($command, $e->getMessage());
  368. }
  369. }
  370. /**
  371. * Upgrade action callback
  372. * @param string $command
  373. * @param array $options
  374. * @param array $params
  375. * @return void
  376. */
  377. public function doUpgrade($command, $options, $params)
  378. {
  379. $options['title'] = "Package upgraded: ";
  380. return $this->doInstall($command, $options, $params);
  381. }
  382. /**
  383. * Updgrade action callback
  384. * @param string $command
  385. * @param array $options
  386. * @param array $params
  387. * @return void
  388. */
  389. public function doUpgradeAll($command, $options, $params)
  390. {
  391. $options['title'] = "Package upgraded: ";
  392. return $this->doInstall($command, $options, $params);
  393. }
  394. /**
  395. * Uninstall package callback
  396. * @param string $command
  397. * @param array $options
  398. * @param array $params
  399. * @return unknown_type
  400. */
  401. public function doUninstall($command, $options, $params)
  402. {
  403. $this->cleanupParams($params);
  404. //$this->splitPackageArgs($params);
  405. try {
  406. if(count($params) != 2) {
  407. throw new Exception("Argument count should be = 2");
  408. }
  409. $channel = $params[0];
  410. $package = $params[1];
  411. $packager = $this->getPackager();
  412. $withDepsMode = !isset($options['nodeps']);
  413. $forceMode = isset($options['force']);
  414. $ftp = empty($options['ftp']) ? false : $options['ftp'];
  415. if($ftp) {
  416. list($cache, $config, $ftpObj) = $packager->getRemoteConf($ftp);
  417. } else {
  418. $cache = $this->getSconfig();
  419. $config = $this->config();
  420. }
  421. $chan = $cache->getChannel($channel);
  422. $channel = $cache->chanName($channel);
  423. if(!$cache->hasPackage($channel, $package)) {
  424. throw new Exception("Package is not installed");
  425. }
  426. $deletedPackages = array();
  427. $list = $packager->getUninstallList($channel, $package, $cache, $config, $withDepsMode);
  428. foreach($list['list'] as $packageData) {
  429. try {
  430. $reqd = $cache->requiredByOtherPackages($packageData['channel'], $packageData['name'], $list['list']);
  431. if(count($reqd)) {
  432. $errMessage = "{$packageData['channel']}/{$packageData['name']} {$packageData['version']} is required by: ";
  433. $t = array();
  434. foreach($reqd as $r) {
  435. $t[] = $r['channel']."/".$r['name']. " ".$r['version'];
  436. }
  437. $errMessage .= implode(", ", $t);
  438. if($forceMode) {
  439. $this->ui()->output("Warning: ".$errMessage);
  440. } else {
  441. throw new Exception($errMessage);
  442. }
  443. }
  444. } catch(Exception $e) {
  445. if($forceMode) {
  446. $this->doError($command, $e->getMessage());
  447. } else {
  448. throw new Exception($e->getMessage());
  449. }
  450. }
  451. }
  452. foreach($list['list'] as $packageData) {
  453. try {
  454. list($chan, $pack) = array($packageData['channel'], $packageData['name']);
  455. $packageName = $packageData['channel'] . "/" . $packageData['name'];
  456. $this->ui()->output("Starting to uninstall $packageName ");
  457. if($ftp) {
  458. $packager->processUninstallPackageFtp($chan, $pack, $cache, $ftpObj);
  459. } else {
  460. $packager->processUninstallPackage($chan, $pack, $cache, $config);
  461. }
  462. $cache->deletePackage($chan, $pack);
  463. $deletedPackages[] = array($chan, $pack);
  464. $this->ui()->output("Package {$packageName} uninstalled");
  465. } catch(Exception $e) {
  466. if($forceMode) {
  467. $this->doError($command, $e->getMessage());
  468. } else {
  469. throw new Exception($e->getMessage());
  470. }
  471. }
  472. }
  473. if($ftp) {
  474. $packager->writeToRemoteCache($cache, $ftpObj);
  475. @unlink($config->getFilename());
  476. }
  477. $out = array($command=>array('data'=>$deletedPackages, 'title'=>'Package deleted: '));
  478. $this->ui()->output($out);
  479. } catch (Exception $e) {
  480. return $this->doError($command, $e->getMessage());
  481. }
  482. }
  483. }