<?php
namespace Croogo\Core\Shell;
use Cake\Console\ConsoleIo;
use Cake\Console\Exception\ConsoleException;
use Cake\Core\Exception\Exception;
use Cake\ORM\Locator\LocatorInterface;
use Cake\Utility\Inflector;
use Croogo\Core\PluginManager;
use Croogo\Core\Shell\CroogoAppShell;
use Croogo\Extensions\CroogoTheme;
use Croogo\Extensions\ExtensionsInstaller;
/**
* Install Shell
*
* Usage:
* ./Console/croogo install plugin https://github.com/shama/myplugin/zipball/master
* ./Console/croogo install plugin shama myplugin
*
* @category Shell
* @package Croogo.Croogo.Console.Command
* @version 1.0
* @author Fahad Ibnay Heylaal <contact@fahad19.com>
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
* @link http://www.croogo.org
*/
class InstallShell extends AppShell
{
/**
* Tmp path to download extensions to
*
* @var string
*/
public $tmpPath = TMP;
/**
* ExtensionsInstaller
*
* @var ExtensionsInstaller
*/
protected $_ExtensionsInstaller = null;
/**
* CroogoPlugin class
*
* @var CroogoPlugin
*/
protected $_CroogoPlugin = null;
/**
* CroogoTheme class
*
* @var CroogoTheme
*/
protected $_CroogoTheme = null;
/**
* Init ExtensionsInstaller, CroogoPlugin, CroogoTheme
*
* @param ConsoleIo $io
* @param LocatorInterface $locator
*/
public function __construct(ConsoleIo $io = null, LocatorInterface $locator = null)
{
parent::__construct($io, $locator);
$this->_ExtensionsInstaller = new ExtensionsInstaller();
$this->_CroogoPlugin = new PluginManager();
$this->_CroogoTheme = new CroogoTheme();
}
/**
* 1. Detects URL or github user/repo or composer package
* 2. Downloads
* 3. Installs extension
* 4. Activates extension
*
* Composer: ./Console/cake install plugin vendor/package
* Github: ./Console/cake install plugin user repo
* Url: ./Console/cake install plugin https://github.com/user/repo
*/
public function main()
{
$type = $this->args[0];
if (strpos($this->args[1], '/') !== false && preg_match('/http[s]*:\/\//i', $this->args[1]) === 0) {
// Composer Install
$ver = isset($this->args[2]) ? $this->args[2] : '*';
$this->out(__d('croogo', 'Installing with Composer...'));
try {
$result = $this->_ExtensionsInstaller->composerInstall([
'package' => $this->args[1],
'version' => $ver,
'type' => $type,
]);
if (!is_array($result)) {
$this->err(__d('croogo', 'Unexpected composerInstall return value'));
return false;
}
if ($result['returnValue'] <> 0) {
$this->err($result['output']);
return false;
}
$ext = substr($this->args[1], strpos($this->args[1], '/') + 1);
$ext = Inflector::camelize($ext);
$shouldActivate = $this->{'_Croogo' . ucfirst($type)}->getData($ext);
if ($shouldActivate !== false) {
$result = $this->dispatchShell('ext', 'activate', $type, $ext, '--quiet');
if ($result) {
$this->out(__d('croogo', 'Package installed and activated.'));
} else {
$this->err(__d('croogo', 'Package installed but not activated.'));
}
}
} catch (Exception $e) {
$this->err($e->getMessage());
}
} else {
// Github / URL Install
$url = '';
if (count($this->args) == 2) {
$url = $this->args[1];
} elseif (count($this->args) == 3) {
$url = 'http://github.com/' . $this->args[1] . '/' . $this->args[2];
}
if ($zip = $this->_download($url)) {
if ($this->_install($type, $zip)) {
if ($this->_activate($type, $zip)) {
$this->out(__d('croogo', 'Extension installed and activated.'));
}
}
}
}
}
/**
* Display help/options
*/
public function getOptionParser()
{
return parent::getOptionParser()
->setDescription(__d('croogo', 'Download, Install & Activate Plugins & Themes'))
->addArguments([
'type' => [
'help' => __d('croogo', 'Extension type'),
'required' => true,
'choices' => ['plugin', 'theme'],
],
'zip_url' => [
'help' => __d('croogo', 'URL to zip file OR github user name'),
'required' => true,
],
'github_package' => [
'help' => __d('croogo', 'Github repo name'),
],
]);
}
/**
* Activates an extension by calling ExtShell
*
* @param string $type Type of extension
* @param string $zip Path to zip file
* @return bool
*/
protected function _activate($type = null, $zip = null)
{
try {
$ext = $this->_ExtensionsInstaller->{'get' . ucfirst($type) . 'Name'}($zip);
$this->dispatchShell('ext', 'activate', $type, $ext, '--quiet');
return true;
} catch (Exception $e) {
$this->err($e->getMessage());
}
return false;
}
/**
* Extracts an extension
*
* @param string $type Type of extension
* @param string $zip Path to zip file
* @return bool
*/
protected function _install($type = null, $zip = null)
{
$this->out(__d('croogo', 'Installing extension...'));
try {
$this->_ExtensionsInstaller->{'extract' . ucfirst($type)}($zip);
return true;
} catch (Exception $e) {
$this->err($e->getMessage());
}
return false;
}
/**
* Download an extension via CURL
*
* @param string $url URL of extension
* @return string Path to zip file
* @throws ConsoleException
*/
protected function _download($url = null)
{
if (empty($url)) {
throw new ConsoleException(__d('croogo', 'Please specify a URL to a zipball extension'));
}
$url = $this->_githubUrl($url);
$filename = uniqid('croogo_') . '.zip';
$zip = $this->tmpPath . $filename;
$this->out(__d('croogo', 'Downloading extension to %s...', $zip));
$res = $this->_shellExec('curl -L ' . $url . ' -o ' . $zip . ' 2>&1');
return $res ? $zip : false;
}
/**
* If Github url return url to zip
*
* @param string $url
* @return string
*/
protected function _githubUrl($url = null)
{
if (strpos($url, 'github.com') === false) {
return $url;
}
if (substr($url, -1) === '/') {
$url = substr($url, 0, -1);
}
if (substr($url, -4) === '.git') {
$url = substr($url, 0, -4);
}
$url = str_replace('git://', 'https://', $url);
return $url . '/zipball/master';
}
/**
* Wrapper for shell_exec() method for testing
*/
protected function _shellExec($cmd)
{
return shell_exec($cmd);
}
}