diff --git a/system/src/Grav/Common/GPM/GPM.php b/system/src/Grav/Common/GPM/GPM.php
index fd82f3642..3a0c4a886 100644
--- a/system/src/Grav/Common/GPM/GPM.php
+++ b/system/src/Grav/Common/GPM/GPM.php
@@ -1,7 +1,9 @@
'user/plugins/%name%', 'themes' => 'user/themes/%name%', 'skeletons' => 'user/'];
+
/**
* Creates a new GPM instance with Local and Remote packages available
* @param boolean $refresh Applies to Remote Packages only and forces a refetch of data
@@ -347,7 +351,20 @@ class GPM extends Iterator
$packages = ['total' => 0, 'not_found' => []];
foreach ($searches as $search) {
+ $repository = '';
+ // if this is an object, get the search data from the key
+ if (is_object($search)) {
+ $search = (array) $search;
+ $key = key($search);
+ $repository = $search[$key];
+ $search = $key;
+ }
+
if ($found = $this->findPackage($search)) {
+ // set override respository if provided
+ if ($repository) {
+ $found->override_repository = $repository;
+ }
if (!isset($packages[$found->package_type])) {
$packages[$found->package_type] = [];
}
@@ -355,7 +372,19 @@ class GPM extends Iterator
$packages[$found->package_type][$found->slug] = $found;
$packages['total']++;
} else {
- $packages['not_found'][] = $search;
+ // make a best guess at the type based on the repo URL
+ if (Utils::contains($repository, '-theme')) {
+ $type = 'themes';
+ } else {
+ $type = 'plugins';
+ }
+
+ $not_found = new \stdClass();
+ $not_found->name = Inflector::camelize($search);
+ $not_found->slug = $search;
+ $not_found->install_path = str_replace('%name%', $search, $this->install_paths[$type]);
+ $not_found->override_repository = $repository;
+ $packages['not_found'][$search] = $not_found;
}
}
diff --git a/system/src/Grav/Common/Plugins.php b/system/src/Grav/Common/Plugins.php
index dd495963e..c33845fac 100644
--- a/system/src/Grav/Common/Plugins.php
+++ b/system/src/Grav/Common/Plugins.php
@@ -47,7 +47,8 @@ class Plugins extends Iterator
$filePath = $this->grav['locator']('plugins://' . $plugin . DS . $plugin . PLUGIN_EXT);
if (!is_file($filePath)) {
- throw new \RuntimeException(sprintf("Plugin '%s' enabled but not found! Try clearing cache with `bin/grav clear-cache`", $plugin));
+ $this->grav['log']->addWarning(sprintf("Plugin '%s' enabled but not found! Try clearing cache with `bin/grav clear-cache`", $plugin));
+ continue;
}
require_once $filePath;
diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php
index 261a73f4a..fd015a0e8 100644
--- a/system/src/Grav/Console/Gpm/InstallCommand.php
+++ b/system/src/Grav/Console/Gpm/InstallCommand.php
@@ -5,6 +5,8 @@ use Grav\Common\Filesystem\Folder;
use Grav\Common\GPM\GPM;
use Grav\Common\GPM\Installer;
use Grav\Common\GPM\Response;
+use Grav\Common\Inflector;
+use Grav\Common\Utils;
use Grav\Console\ConsoleTrait;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
@@ -12,6 +14,10 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;
+use Symfony\Component\Console\Question\ChoiceQuestion;
+use Symfony\Component\Yaml\Yaml;
+
+define('GIT_REGEX', '/http[s]?:\/\/(?:.*@)?(github|bitbucket)(?:.org|.com)\/.*\/(.*)/');
/**
* Class InstallCommand
@@ -42,6 +48,9 @@ class InstallCommand extends Command
*/
protected $tmp;
+ protected $local_config;
+
+
/**
*
*/
@@ -93,6 +102,11 @@ class InstallCommand extends Command
$packages = array_map('strtolower', $this->input->getArgument('package'));
$this->data = $this->gpm->findPackages($packages);
+ $local_config_file = exec('eval echo ~/.grav/config');
+ if (file_exists($local_config_file)) {
+ $this->local_config = Yaml::parse($local_config_file);
+ }
+
if (
!Installer::isGravInstance($this->destination) ||
!Installer::isValidDestination($this->destination, [Installer::EXISTS, Installer::IS_LINK])
@@ -111,7 +125,7 @@ class InstallCommand extends Command
if (count($this->data['not_found'])) {
$this->output->writeln("These packages were not found on Grav: " . implode(', ',
- $this->data['not_found']) . "");
+ array_keys($this->data['not_found'])) . "");
}
unset($this->data['not_found']);
@@ -119,11 +133,131 @@ class InstallCommand extends Command
foreach ($this->data as $data) {
foreach ($data as $package) {
- $version = isset($package->available) ? $package->available : $package->version;
- $this->output->writeln("Preparing to install " . $package->name . " [v" . $version . "]");
- $this->output->write(" |- Downloading package... 0%");
- $this->file = $this->downloadPackage($package);
+ //Check for dependencies
+ if (isset($package->dependencies)) {
+ $this->output->writeln("Package " . $package->name . " has ". count($package->dependencies) . " required dependencies that must be installed first...");
+ $this->output->writeln('');
+
+ $dependency_data = $this->gpm->findPackages($package->dependencies);
+
+ if (!$dependency_data['total']) {
+ $this->output->writeln("No dependencies found...");
+ $this->output->writeln('');
+ } else {
+ unset($dependency_data['total']);
+
+ foreach($dependency_data as $type => $dep_data) {
+ foreach($dep_data as $name => $dep_package) {
+
+ $this->processPackage($dep_package);
+ }
+ }
+ }
+ }
+
+ $this->processPackage($package);
+ }
+ }
+
+ // clear cache after successful upgrade
+ $this->clearCache();
+ }
+
+ /**
+ * @param $package
+ */
+ private function processPackage($package)
+ {
+ $install_options = ['GPM'];
+
+ // if no name, not found in GPM
+ if (!isset($package->version)) {
+ unset($install_options[0]);
+ }
+ // if local config found symlink is a valid option
+ if (isset($this->local_config)) {
+ $install_options[] = 'Symlink';
+ }
+ // if override set, can install via git
+ if (isset($package->override_repository)) {
+ $install_options[] = 'Git';
+ }
+
+ // reindex list
+ $install_options = array_values($install_options);
+
+ if (count($install_options) == 0) {
+ // no valid install options - error and return
+ $this->output->writeln("not valid installation methods found!");
+ return;
+ } elseif (count($install_options) == 1) {
+ // only one option, use it...
+ $method = $install_options[0];
+ } else {
+ $helper = $this->getHelper('question');
+ $question = new ChoiceQuestion(
+ 'Please select installation method for ' . $package->name . ' ('.$install_options[0].' is default)', array_values($install_options), 0
+ );
+ $question->setErrorMessage('Method %s is invalid');
+ $method = $helper->ask($this->input, $this->output, $question);
+ }
+
+ $this->output->writeln('');
+
+ $method_name = 'process'.$method;
+
+ $this->$method_name($package);
+ }
+
+ /**
+ * @param $package
+ *
+ * @return array
+ */
+ private function getGitRegexMatches($package)
+ {
+ if (isset($package->override_repository)) {
+ $repository = $package->override_repository;
+ } elseif (isset($package->repository)) {
+ $repository = $package->repository;
+ } else {
+ return false;
+ }
+
+ preg_match(GIT_REGEX, $repository, $matches);
+
+ return $matches;
+ }
+
+ /**
+ * @param $package
+ */
+ private function processSymlink($package)
+ {
+
+ exec('cd ' . $this->destination);
+
+ $to = $this->destination . DS . $package->install_path;
+
+ $matches = $this->getGitRegexMatches($package);
+
+ $this->output->writeln("Preparing to Symlink " . $package->name . "");
+ $this->output->write(" |- Checking source... ");
+
+ foreach ($this->local_config as $path) {
+
+ if (Utils::endsWith($matches[2], '.git')) {
+ $repo_dir = preg_replace('/\.git$/', '', $matches[2]);
+ } else {
+ $repo_dir = $matches[2];
+ }
+
+ $from = rtrim($path, '/') . '/' . $repo_dir;
+
+ if (file_exists($from)) {
+
+ $this->output->writeln("ok");
$this->output->write(" |- Checking destination... ");
$checks = $this->checkDestination($package);
@@ -132,21 +266,86 @@ class InstallCommand extends Command
$this->output->writeln(" '- Installation failed or aborted.");
$this->output->writeln('');
} else {
- $this->output->write(" |- Installing package... ");
- $installation = $this->installPackage($package);
- if (!$installation) {
- $this->output->writeln(" '- Installation failed or aborted.");
+ if (file_exists($to)) {
+ $this->output->writeln(" '- Symlink cannot overwrite an existing package, please remove first");
$this->output->writeln('');
} else {
+ symlink($from, $to);
+
+ // extra white spaces to clear out the buffer properly
+ $this->output->writeln(" |- Symlinking package... ok ");
+
$this->output->writeln(" '- Success! ");
$this->output->writeln('');
}
+
+
}
+ return;
}
}
+ $this->output->writeln("not found!");
+ $this->output->writeln(" '- Installation failed or aborted.");
+ }
- // clear cache after successful upgrade
- $this->clearCache();
+ /**
+ * @param $package
+ */
+ private function processGit($package)
+ {
+ $matches = $this->getGitRegexMatches($package);
+
+ $to = $this->destination . DS . $package->install_path;
+
+ $this->output->writeln("Preparing to Git clone " . $package->name . " from " . $matches[0]);
+
+ $this->output->write(" |- Checking destination... ");
+ $checks = $this->checkDestination($package);
+
+ if (!$checks) {
+ $this->output->writeln(" '- Installation failed or aborted.");
+ $this->output->writeln('');
+ } else {
+ $cmd = 'cd ' . $this->destination . ' && git clone ' . $matches[0] . ' ' . $package->install_path;
+ exec($cmd);
+
+ // extra white spaces to clear out the buffer properly
+ $this->output->writeln(" |- Cloning package... ok ");
+
+ $this->output->writeln(" '- Success! ");
+ $this->output->writeln('');
+ }
+ }
+
+ /**
+ * @param $package
+ */
+ private function processGPM($package)
+ {
+ $version = isset($package->available) ? $package->available : $package->version;
+
+ $this->output->writeln("Preparing to install " . $package->name . " [v" . $version . "]");
+
+ $this->output->write(" |- Downloading package... 0%");
+ $this->file = $this->downloadPackage($package);
+
+ $this->output->write(" |- Checking destination... ");
+ $checks = $this->checkDestination($package);
+
+ if (!$checks) {
+ $this->output->writeln(" '- Installation failed or aborted.");
+ $this->output->writeln('');
+ } else {
+ $this->output->write(" |- Installing package... ");
+ $installation = $this->installPackage($package);
+ if (!$installation) {
+ $this->output->writeln(" '- Installation failed or aborted.");
+ $this->output->writeln('');
+ } else {
+ $this->output->writeln(" '- Success! ");
+ $this->output->writeln('');
+ }
+ }
}
/**
@@ -218,6 +417,8 @@ class InstallCommand extends Command
$this->output->writeln(" | '- You decided to not delete the symlink automatically.");
return false;
+ } else {
+ unlink($this->destination . DS . $package->install_path);
}
}