Addon.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. <?php
  2. namespace app\admin\command;
  3. use think\addons\AddonException;
  4. use think\addons\Service;
  5. use think\console\Command;
  6. use think\console\Input;
  7. use think\console\input\Option;
  8. use think\console\Output;
  9. use think\Db;
  10. use think\Exception;
  11. class Addon extends Command
  12. {
  13. protected function configure()
  14. {
  15. $this
  16. ->setName('addon')
  17. ->addOption('name', 'a', Option::VALUE_REQUIRED, 'addon name', null)
  18. ->addOption('action', 'c', Option::VALUE_REQUIRED, 'action(create/enable/disable/install/uninstall/refresh/upgrade/package)', 'create')
  19. ->addOption('force', 'f', Option::VALUE_OPTIONAL, 'force override', null)
  20. ->addOption('release', 'r', Option::VALUE_OPTIONAL, 'addon release version', null)
  21. ->setDescription('Addon manager');
  22. }
  23. protected function execute(Input $input, Output $output)
  24. {
  25. $name = $input->getOption('name') ?: '';
  26. $action = $input->getOption('action') ?: '';
  27. //强制覆盖
  28. $force = $input->getOption('force');
  29. //版本
  30. $release = $input->getOption('release') ?: '';
  31. include dirname(__DIR__) . DS . 'common.php';
  32. if (!$name)
  33. {
  34. throw new Exception('Addon name could not be empty');
  35. }
  36. if (!$action || !in_array($action, ['create', 'disable', 'enable', 'install', 'uninstall', 'refresh', 'upgrade', 'package']))
  37. {
  38. throw new Exception('Please input correct action name');
  39. }
  40. // 查询一次SQL,判断连接是否正常
  41. Db::execute("SELECT 1");
  42. $addonDir = ADDON_PATH . $name . DS;
  43. switch ($action)
  44. {
  45. case 'create':
  46. //非覆盖模式时如果存在则报错
  47. if (is_dir($addonDir) && !$force)
  48. {
  49. throw new Exception("addon already exists!\nIf you need to create again, use the parameter --force=true ");
  50. }
  51. //如果存在先移除
  52. if (is_dir($addonDir))
  53. {
  54. rmdirs($addonDir);
  55. }
  56. mkdir($addonDir);
  57. $data = [
  58. 'name' => $name,
  59. 'addon' => $name,
  60. 'addonClassName' => ucfirst($name)
  61. ];
  62. $this->writeToFile("addon", $data, $addonDir . ucfirst($name) . '.php');
  63. $this->writeToFile("config", $data, $addonDir . 'config.php');
  64. $this->writeToFile("info", $data, $addonDir . 'info.ini');
  65. $output->info("Create Successed!");
  66. break;
  67. case 'disable':
  68. case 'enable':
  69. try
  70. {
  71. //调用启用、禁用的方法
  72. Service::$action($name, 0);
  73. }
  74. catch (AddonException $e)
  75. {
  76. if ($e->getCode() != -3)
  77. {
  78. throw new Exception($e->getMessage());
  79. }
  80. //如果有冲突文件则提醒
  81. $data = $e->getData();
  82. foreach ($data['conflictlist'] as $k => $v)
  83. {
  84. $output->warning($v);
  85. }
  86. $output->info("Are you sure you want to " . ($action == 'enable' ? 'override' : 'delete') . " all those files? Type 'yes' to continue: ");
  87. $line = fgets(STDIN);
  88. if (trim($line) != 'yes')
  89. {
  90. throw new Exception("Operation is aborted!");
  91. }
  92. //调用启用、禁用的方法
  93. Service::$action($name, 1);
  94. }
  95. catch (Exception $e)
  96. {
  97. throw new Exception($e->getMessage());
  98. }
  99. $output->info(ucfirst($action) . " Successed!");
  100. break;
  101. case 'install':
  102. //非覆盖模式时如果存在则报错
  103. if (is_dir($addonDir) && !$force)
  104. {
  105. throw new Exception("addon already exists!\nIf you need to install again, use the parameter --force=true ");
  106. }
  107. //如果存在先移除
  108. if (is_dir($addonDir))
  109. {
  110. rmdirs($addonDir);
  111. }
  112. try
  113. {
  114. Service::install($name, 0, ['version' => $release]);
  115. }
  116. catch (AddonException $e)
  117. {
  118. if ($e->getCode() != -3)
  119. {
  120. throw new Exception($e->getMessage());
  121. }
  122. //如果有冲突文件则提醒
  123. $data = $e->getData();
  124. foreach ($data['conflictlist'] as $k => $v)
  125. {
  126. $output->warning($v);
  127. }
  128. $output->info("Are you sure you want to override all those files? Type 'yes' to continue: ");
  129. $line = fgets(STDIN);
  130. if (trim($line) != 'yes')
  131. {
  132. throw new Exception("Operation is aborted!");
  133. }
  134. Service::install($name, 1, ['version' => $release]);
  135. }
  136. catch (Exception $e)
  137. {
  138. throw new Exception($e->getMessage());
  139. }
  140. $output->info("Install Successed!");
  141. break;
  142. case 'uninstall':
  143. //非覆盖模式时如果存在则报错
  144. if (!$force)
  145. {
  146. throw new Exception("If you need to uninstall addon, use the parameter --force=true ");
  147. }
  148. try
  149. {
  150. Service::uninstall($name, 0);
  151. }
  152. catch (AddonException $e)
  153. {
  154. if ($e->getCode() != -3)
  155. {
  156. throw new Exception($e->getMessage());
  157. }
  158. //如果有冲突文件则提醒
  159. $data = $e->getData();
  160. foreach ($data['conflictlist'] as $k => $v)
  161. {
  162. $output->warning($v);
  163. }
  164. $output->info("Are you sure you want to delete all those files? Type 'yes' to continue: ");
  165. $line = fgets(STDIN);
  166. if (trim($line) != 'yes')
  167. {
  168. throw new Exception("Operation is aborted!");
  169. }
  170. Service::uninstall($name, 1);
  171. }
  172. catch (Exception $e)
  173. {
  174. throw new Exception($e->getMessage());
  175. }
  176. $output->info("Uninstall Successed!");
  177. break;
  178. case 'refresh':
  179. Service::refresh();
  180. $output->info("Refresh Successed!");
  181. break;
  182. case 'upgrade':
  183. Service::upgrade($name, ['version' => $release]);
  184. $output->info("Upgrade Successed!");
  185. break;
  186. case 'package':
  187. $infoFile = $addonDir . 'info.ini';
  188. if (!is_file($infoFile))
  189. {
  190. throw new Exception(__('Addon info file was not found'));
  191. }
  192. $info = get_addon_info($name);
  193. if (!$info)
  194. {
  195. throw new Exception(__('Addon info file data incorrect'));
  196. }
  197. $infoname = isset($info['name']) ? $info['name'] : '';
  198. if (!$infoname || !preg_match("/^[a-z]+$/i", $infoname) || $infoname != $name)
  199. {
  200. throw new Exception(__('Addon info name incorrect'));
  201. }
  202. $infoversion = isset($info['version']) ? $info['version'] : '';
  203. if (!$infoversion || !preg_match("/^\d+\.\d+\.\d+$/i", $infoversion))
  204. {
  205. throw new Exception(__('Addon info version incorrect'));
  206. }
  207. $addonTmpDir = RUNTIME_PATH . 'addons' . DS;
  208. if (!is_dir($addonTmpDir))
  209. {
  210. @mkdir($addonTmpDir, 0755, true);
  211. }
  212. $addonFile = $addonTmpDir . $infoname . '-' . $infoversion . '.zip';
  213. if (!class_exists('ZipArchive'))
  214. {
  215. throw new Exception(__('ZinArchive not install'));
  216. }
  217. $zip = new \ZipArchive;
  218. $zip->open($addonFile, \ZipArchive::CREATE | \ZipArchive::OVERWRITE);
  219. $files = new \RecursiveIteratorIterator(
  220. new \RecursiveDirectoryIterator($addonDir), \RecursiveIteratorIterator::LEAVES_ONLY
  221. );
  222. foreach ($files as $name => $file)
  223. {
  224. if (!$file->isDir())
  225. {
  226. $filePath = $file->getRealPath();
  227. $relativePath = substr($filePath, strlen($addonDir));
  228. if (!in_array($file->getFilename(), ['.git', '.DS_Store', 'Thumbs.db']))
  229. {
  230. $zip->addFile($filePath, $relativePath);
  231. }
  232. }
  233. }
  234. $zip->close();
  235. $output->info("Package Successed!");
  236. break;
  237. default :
  238. break;
  239. }
  240. }
  241. /**
  242. * 写入到文件
  243. * @param string $name
  244. * @param array $data
  245. * @param string $pathname
  246. * @return mixed
  247. */
  248. protected function writeToFile($name, $data, $pathname)
  249. {
  250. $search = $replace = [];
  251. foreach ($data as $k => $v)
  252. {
  253. $search[] = "{%{$k}%}";
  254. $replace[] = $v;
  255. }
  256. $stub = file_get_contents($this->getStub($name));
  257. $content = str_replace($search, $replace, $stub);
  258. if (!is_dir(dirname($pathname)))
  259. {
  260. mkdir(strtolower(dirname($pathname)), 0755, true);
  261. }
  262. return file_put_contents($pathname, $content);
  263. }
  264. /**
  265. * 获取基础模板
  266. * @param string $name
  267. * @return string
  268. */
  269. protected function getStub($name)
  270. {
  271. return __DIR__ . '/Addon/stubs/' . $name . '.stub';
  272. }
  273. }