IndexCommand.php 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. <?php
  2. /**
  3. * @package Grav\Console\Gpm
  4. *
  5. * @copyright Copyright (C) 2015 - 2019 Trilby Media, LLC. All rights reserved.
  6. * @license MIT License; see LICENSE file for details.
  7. */
  8. namespace Grav\Console\Gpm;
  9. use Grav\Common\GPM\Remote\Package;
  10. use Grav\Common\GPM\GPM;
  11. use Grav\Common\GPM\Remote\Packages;
  12. use Grav\Common\Utils;
  13. use Grav\Console\ConsoleCommand;
  14. use League\CLImate\CLImate;
  15. use Symfony\Component\Console\Input\InputOption;
  16. class IndexCommand extends ConsoleCommand
  17. {
  18. /** @var array */
  19. protected $data;
  20. /** @var GPM */
  21. protected $gpm;
  22. /** @var array */
  23. protected $options;
  24. /** @var array */
  25. protected $sortKeys = ['name', 'slug', 'author', 'date'];
  26. protected function configure()
  27. {
  28. $this
  29. ->setName('index')
  30. ->addOption(
  31. 'force',
  32. 'f',
  33. InputOption::VALUE_NONE,
  34. 'Force re-fetching the data from remote'
  35. )
  36. ->addOption(
  37. 'filter',
  38. 'F',
  39. InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
  40. 'Allows to limit the results based on one or multiple filters input. This can be either portion of a name/slug or a regex'
  41. )
  42. ->addOption(
  43. 'themes-only',
  44. 'T',
  45. InputOption::VALUE_NONE,
  46. 'Filters the results to only Themes'
  47. )
  48. ->addOption(
  49. 'plugins-only',
  50. 'P',
  51. InputOption::VALUE_NONE,
  52. 'Filters the results to only Plugins'
  53. )
  54. ->addOption(
  55. 'updates-only',
  56. 'U',
  57. InputOption::VALUE_NONE,
  58. 'Filters the results to Updatable Themes and Plugins only'
  59. )
  60. ->addOption(
  61. 'installed-only',
  62. 'I',
  63. InputOption::VALUE_NONE,
  64. 'Filters the results to only the Themes and Plugins you have installed'
  65. )
  66. ->addOption(
  67. 'sort',
  68. 's',
  69. InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
  70. 'Allows to sort (ASC) the results based on one or multiple keys. SORT can be either "name", "slug", "author", "date"',
  71. ['date']
  72. )
  73. ->addOption(
  74. 'desc',
  75. 'D',
  76. InputOption::VALUE_NONE,
  77. 'Reverses the order of the output.'
  78. )
  79. ->setDescription('Lists the plugins and themes available for installation')
  80. ->setHelp('The <info>index</info> command lists the plugins and themes available for installation')
  81. ;
  82. }
  83. protected function serve()
  84. {
  85. $this->options = $this->input->getOptions();
  86. $this->gpm = new GPM($this->options['force']);
  87. $this->displayGPMRelease();
  88. $this->data = $this->gpm->getRepository();
  89. $data = $this->filter($this->data);
  90. $climate = new CLImate;
  91. $climate->extend('Grav\Console\TerminalObjects\Table');
  92. if (!$data) {
  93. $this->output->writeln('No data was found in the GPM repository stored locally.');
  94. $this->output->writeln('Please try clearing cache and running the <green>bin/gpm index -f</green> command again');
  95. $this->output->writeln('If this doesn\'t work try tweaking your GPM system settings.');
  96. $this->output->writeln('');
  97. $this->output->writeln('For more help go to:');
  98. $this->output->writeln(' -> <yellow>https://learn.getgrav.org/troubleshooting/common-problems#cannot-connect-to-the-gpm</yellow>');
  99. die;
  100. }
  101. foreach ($data as $type => $packages) {
  102. $this->output->writeln('<green>' . strtoupper($type) . '</green> [ ' . \count($packages) . ' ]');
  103. $packages = $this->sort($packages);
  104. if (!empty($packages)) {
  105. $table = [];
  106. $index = 0;
  107. foreach ($packages as $slug => $package) {
  108. $row = [
  109. 'Count' => $index++ + 1,
  110. 'Name' => '<cyan>' . Utils::truncate($package->name, 20, false, ' ', '...') . '</cyan> ',
  111. 'Slug' => $slug,
  112. 'Version'=> $this->version($package),
  113. 'Installed' => $this->installed($package)
  114. ];
  115. $table[] = $row;
  116. }
  117. $climate->table($table);
  118. }
  119. $this->output->writeln('');
  120. }
  121. $this->output->writeln('You can either get more informations about a package by typing:');
  122. $this->output->writeln(" <green>{$this->argv} info <cyan><package></cyan></green>");
  123. $this->output->writeln('');
  124. $this->output->writeln('Or you can install a package by typing:');
  125. $this->output->writeln(" <green>{$this->argv} install <cyan><package></cyan></green>");
  126. $this->output->writeln('');
  127. }
  128. /**
  129. * @param Package $package
  130. *
  131. * @return string
  132. */
  133. private function version($package)
  134. {
  135. $list = $this->gpm->{'getUpdatable' . ucfirst($package->package_type)}();
  136. $package = $list[$package->slug] ?? $package;
  137. $type = ucfirst(preg_replace('/s$/', '', $package->package_type));
  138. $updatable = $this->gpm->{'is' . $type . 'Updatable'}($package->slug);
  139. $installed = $this->gpm->{'is' . $type . 'Installed'}($package->slug);
  140. $local = $this->gpm->{'getInstalled' . $type}($package->slug);
  141. if (!$installed || !$updatable) {
  142. $version = $installed ? $local->version : $package->version;
  143. return "v<green>{$version}</green>";
  144. }
  145. if ($updatable) {
  146. return "v<red>{$package->version}</red> <cyan>-></cyan> v<green>{$package->available}</green>";
  147. }
  148. return '';
  149. }
  150. /**
  151. * @param Package $package
  152. *
  153. * @return string
  154. */
  155. private function installed($package)
  156. {
  157. $package = $list[$package->slug] ?? $package;
  158. $type = ucfirst(preg_replace('/s$/', '', $package->package_type));
  159. $method = 'is' . $type . 'Installed';
  160. $installed = $this->gpm->{$method}($package->slug);
  161. return !$installed ? '<magenta>not installed</magenta>' : '<cyan>installed</cyan>';
  162. }
  163. /**
  164. * @param array $data
  165. *
  166. * @return mixed
  167. */
  168. public function filter($data)
  169. {
  170. // filtering and sorting
  171. if ($this->options['plugins-only']) {
  172. unset($data['themes']);
  173. }
  174. if ($this->options['themes-only']) {
  175. unset($data['plugins']);
  176. }
  177. $filter = [
  178. $this->options['filter'],
  179. $this->options['installed-only'],
  180. $this->options['updates-only'],
  181. $this->options['desc']
  182. ];
  183. if (\count(array_filter($filter))) {
  184. foreach ($data as $type => $packages) {
  185. foreach ($packages as $slug => $package) {
  186. $filter = true;
  187. // Filtering by string
  188. if ($this->options['filter']) {
  189. $filter = preg_grep('/(' . implode('|', $this->options['filter']) . ')/i', [$slug, $package->name]);
  190. }
  191. // Filtering updatables only
  192. if ($filter && $this->options['installed-only']) {
  193. $method = ucfirst(preg_replace('/s$/', '', $package->package_type));
  194. $function = 'is' . $method . 'Installed';
  195. $filter = $this->gpm->{$function}($package->slug);
  196. }
  197. // Filtering updatables only
  198. if ($filter && $this->options['updates-only']) {
  199. $method = ucfirst(preg_replace('/s$/', '', $package->package_type));
  200. $function = 'is' . $method . 'Updatable';
  201. $filter = $this->gpm->{$function}($package->slug);
  202. }
  203. if (!$filter) {
  204. unset($data[$type][$slug]);
  205. }
  206. }
  207. }
  208. }
  209. return $data;
  210. }
  211. /**
  212. * @param Packages $packages
  213. */
  214. public function sort($packages)
  215. {
  216. foreach ($this->options['sort'] as $key) {
  217. $packages = $packages->sort(function ($a, $b) use ($key) {
  218. switch ($key) {
  219. case 'author':
  220. return strcmp($a->{$key}['name'], $b->{$key}['name']);
  221. break;
  222. default:
  223. return strcmp($a->$key, $b->$key);
  224. }
  225. }, $this->options['desc'] ? true : false);
  226. }
  227. return $packages;
  228. }
  229. }