setName('index') ->addOption( 'force', 'f', InputOption::VALUE_NONE, 'Force re-fetching the data from remote' ) ->addOption( 'filter', 'F', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Allows to limit the results based on one or multiple filters input. This can be either portion of a name/slug or a regex' ) ->addOption( 'themes-only', 'T', InputOption::VALUE_NONE, 'Filters the results to only Themes' ) ->addOption( 'plugins-only', 'P', InputOption::VALUE_NONE, 'Filters the results to only Plugins' ) ->addOption( 'updates-only', 'U', InputOption::VALUE_NONE, 'Filters the results to Updatable Themes and Plugins only' ) ->addOption( 'installed-only', 'I', InputOption::VALUE_NONE, 'Filters the results to only the Themes and Plugins you have installed' ) ->addOption( 'sort', 's', InputOption::VALUE_REQUIRED, 'Allows to sort (ASC) the results. SORT can be either "name", "slug", "author", "date"', 'date' ) ->addOption( 'desc', 'D', InputOption::VALUE_NONE, 'Reverses the order of the output.' ) ->setDescription('Lists the plugins and themes available for installation') ->setHelp('The index command lists the plugins and themes available for installation') ; } /** * @return int */ protected function serve(): int { $input = $this->getInput(); $this->options = $input->getOptions(); $this->gpm = new GPM($this->options['force']); $this->displayGPMRelease(); $this->data = $this->gpm->getRepository(); $data = $this->filter($this->data); $io = $this->getIO(); if (count($data) === 0) { $io->writeln('No data was found in the GPM repository stored locally.'); $io->writeln('Please try clearing cache and running the bin/gpm index -f command again'); $io->writeln('If this doesn\'t work try tweaking your GPM system settings.'); $io->newLine(); $io->writeln('For more help go to:'); $io->writeln(' -> https://learn.getgrav.org/troubleshooting/common-problems#cannot-connect-to-the-gpm'); return 1; } foreach ($data as $type => $packages) { $io->writeln('' . strtoupper($type) . ' [ ' . count($packages) . ' ]'); $packages = $this->sort($packages); if (!empty($packages)) { $io->section('Packages table'); $table = new Table($io); $table->setHeaders(['Count', 'Name', 'Slug', 'Version', 'Installed']); $index = 0; foreach ($packages as $slug => $package) { $row = [ 'Count' => $index++ + 1, 'Name' => '' . Utils::truncate($package->name, 20, false, ' ', '...') . ' ', 'Slug' => $slug, 'Version'=> $this->version($package), 'Installed' => $this->installed($package) ]; $table->addRow($row); } $table->render(); } $io->newLine(); } $io->writeln('You can either get more informations about a package by typing:'); $io->writeln(" {$this->argv} info "); $io->newLine(); $io->writeln('Or you can install a package by typing:'); $io->writeln(" {$this->argv} install "); $io->newLine(); return 0; } /** * @param Package $package * @return string */ private function version(Package $package): string { $list = $this->gpm->{'getUpdatable' . ucfirst($package->package_type)}(); $package = $list[$package->slug] ?? $package; $type = ucfirst(preg_replace('/s$/', '', $package->package_type)); $updatable = $this->gpm->{'is' . $type . 'Updatable'}($package->slug); $installed = $this->gpm->{'is' . $type . 'Installed'}($package->slug); $local = $this->gpm->{'getInstalled' . $type}($package->slug); if (!$installed || !$updatable) { $version = $installed ? $local->version : $package->version; return "v{$version}"; } return "v{$package->version} -> v{$package->available}"; } /** * @param Package $package * @return string */ private function installed(Package $package): string { $package = $list[$package->slug] ?? $package; $type = ucfirst(preg_replace('/s$/', '', $package->package_type)); $method = 'is' . $type . 'Installed'; $installed = $this->gpm->{$method}($package->slug); return !$installed ? 'not installed' : 'installed'; } /** * @param Packages $data * @return Packages */ public function filter(Packages $data): Packages { // filtering and sorting if ($this->options['plugins-only']) { unset($data['themes']); } if ($this->options['themes-only']) { unset($data['plugins']); } $filter = [ $this->options['filter'], $this->options['installed-only'], $this->options['updates-only'], $this->options['desc'] ]; if (count(array_filter($filter))) { foreach ($data as $type => $packages) { foreach ($packages as $slug => $package) { $filter = true; // Filtering by string if ($this->options['filter']) { $filter = preg_grep('/(' . implode('|', $this->options['filter']) . ')/i', [$slug, $package->name]); } // Filtering updatables only if ($filter && $this->options['installed-only']) { $method = ucfirst(preg_replace('/s$/', '', $package->package_type)); $function = 'is' . $method . 'Installed'; $filter = $this->gpm->{$function}($package->slug); } // Filtering updatables only if ($filter && $this->options['updates-only']) { $method = ucfirst(preg_replace('/s$/', '', $package->package_type)); $function = 'is' . $method . 'Updatable'; $filter = $this->gpm->{$function}($package->slug); } if (!$filter) { unset($data[$type][$slug]); } } } } return $data; } /** * @param AbstractPackageCollection|Plugins|Themes $packages * @return array */ public function sort(AbstractPackageCollection $packages): array { $key = $this->options['sort']; // Sorting only works once. return $packages->sort( function ($a, $b) use ($key) { switch ($key) { case 'author': return strcmp($a->{$key}['name'], $b->{$key}['name']); default: return strcmp($a->$key, $b->$key); } }, $this->options['desc'] ? true : false ); } }