diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index 651b3c9a8..7058fafbe 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -2,6 +2,7 @@ namespace Grav\Console\Gpm; use Grav\Common\GPM\GPM; +use Grav\Common\GPM\Installer; use Grav\Common\GPM\Response; use Grav\Console\ConsoleTrait; use Symfony\Component\Console\Command\Command; @@ -11,7 +12,8 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\ConfirmationQuestion; -class InstallCommand extends Command { +class InstallCommand extends Command +{ use ConsoleTrait; protected $data; @@ -19,38 +21,40 @@ class InstallCommand extends Command { protected $destination; protected $file; - protected function configure() { + protected function configure() + { $this ->setName("install") ->addOption( - 'force', - 'f', - InputOption::VALUE_NONE, - 'Force re-fetching the data from remote' - ) + 'force', + 'f', + InputOption::VALUE_NONE, + 'Force re-fetching the data from remote' + ) ->addOption( - 'all-yes', - 'y', - InputOption::VALUE_NONE, - 'Assumes yes (or best approach) instead of prompting' - ) + 'all-yes', + 'y', + InputOption::VALUE_NONE, + 'Assumes yes (or best approach) instead of prompting' + ) ->addOption( - 'destination', - 'd', - InputOption::VALUE_OPTIONAL, - 'The destination where the package should be installed at. By default this would be where the grav instance has been launched from', - GRAV_ROOT - ) + 'destination', + 'd', + InputOption::VALUE_OPTIONAL, + 'The destination where the package should be installed at. By default this would be where the grav instance has been launched from', + GRAV_ROOT + ) ->addArgument( - 'package', - InputArgument::IS_ARRAY|InputArgument::REQUIRED, - 'The package of which more informations are desired. Use the "index" command for a list of packages' - ) + 'package', + InputArgument::IS_ARRAY|InputArgument::REQUIRED, + 'The package of which more informations are desired. Use the "index" command for a list of packages' + ) ->setDescription("Performs the installation of plugins and themes") ->setHelp('The install command allows to install plugins and themes'); } - protected function execute(InputInterface $input, OutputInterface $output) { + protected function execute(InputInterface $input, OutputInterface $output) + { $this->setupConsole($input, $output); $this->gpm = new GPM($this->input->getOption('force')); @@ -59,7 +63,17 @@ class InstallCommand extends Command { $packages = array_map('strtolower', $this->input->getArgument('package')); $this->data = $this->gpm->findPackages($packages); - $this->isGravInstance($this->destination); + if ( + !Installer::isGravInstance($this->destination) || + !Installer::isValidDestination($this->destination, [Installer::EXISTS, Installer::IS_LINK]) + ) { + $this->output->writeln(''); + $this->output->writeln("ERROR: " . Installer::lastErrorMsg()); + $this->output->writeln(" ".$this->destination.""); + $this->output->writeln(''); + + exit; + } $this->output->writeln(''); @@ -76,8 +90,8 @@ class InstallCommand extends Command { unset($this->data['not_found']); unset($this->data['total']); - foreach ($this->data as $type => $data) { - foreach ($data as $slug => $package) { + foreach ($this->data as $data) { + foreach ($data as $package) { $this->output->writeln("Preparing to install " . $package->name . " [v" . $package->version . "]"); $this->output->write(" |- Downloading package... 0%"); @@ -108,8 +122,8 @@ class InstallCommand extends Command { $this->rrmdir($this->destination . DS . 'tmp-gpm'); } - private function downloadPackage($package) { - + private function downloadPackage($package) + { $tmp = $this->destination . DS . 'tmp-gpm'; $filename = $package->slug . basename($package->download); $output = Response::get($package->download, [], [$this, 'progress']); @@ -128,12 +142,14 @@ class InstallCommand extends Command { return $tmp . DS . $filename; } - private function checkDestination($package) { - $destination = $this->destination . DS . $package->install_path; + private function checkDestination($package) + { $questionHelper = $this->getHelper('question'); $skipPrompt = $this->input->getOption('all-yes'); - if (is_dir($destination) && !is_link($destination)) { + Installer::isValidDestination($this->destination . DS . $package->install_path); + + if (Installer::lastErrorCode() == Installer::EXISTS) { if (!$skipPrompt) { $this->output->write("\x0D"); $this->output->writeln(" |- Checking destination... exists"); @@ -143,20 +159,19 @@ class InstallCommand extends Command { if (!$answer) { $this->output->writeln(" | '- You decided to not overwrite the already installed package."); + return false; } } - - $this->rrmdir($destination); - @mkdir($destination, 0777, true); } - if (is_link($destination)) { + if (Installer::lastErrorCode() == Installer::IS_LINK) { $this->output->write("\x0D"); $this->output->writeln(" |- Checking destination... symbolic link"); if ($skipPrompt) { $this->output->writeln(" | '- Skipped automatically."); + return false; } @@ -165,10 +180,9 @@ class InstallCommand extends Command { if (!$answer) { $this->output->writeln(" | '- You decided to not delete the symlink automatically."); + return false; } - - @unlink($destination); } $this->output->write("\x0D"); @@ -177,46 +191,42 @@ class InstallCommand extends Command { return true; } - private function installPackage($package) { - $destination = $this->destination . DS . $package->install_path; - $zip = new \ZipArchive; - $openZip = $zip->open($this->file); - $tmp = $this->destination . DS . 'tmp-gpm'; + private function installPackage($package) + { + $installer = Installer::install($this->file, $this->destination, ['install_path' => $package->install_path]); + $errorCode = Installer::lastErrorCode(); - if (!$openZip) { + if ($errorCode & (Installer::ZIP_OPEN_ERROR | Installer::ZIP_EXTRACT_ERROR)) { $this->output->write("\x0D"); // extra white spaces to clear out the buffer properly $this->output->writeln(" |- Installing package... error "); - $this->output->writeln(" | '- Unable to open the downloaded package: " . $package->download . ""); + $this->output->writeln(" | '- " . $installer->lastErrorMsg()); return false; } - $innerFolder = $zip->getNameIndex(0); - - $zip->extractTo($tmp); - $zip->close(); - - rename($tmp . DS . $innerFolder, $destination); - $this->output->write("\x0D"); // extra white spaces to clear out the buffer properly $this->output->writeln(" |- Installing package... ok "); + return true; } - public function progress($progress) { + public function progress($progress) + { $this->output->write("\x0D"); $this->output->write(" |- Downloading package... " . str_pad($progress['percent'], 5, " ", STR_PAD_LEFT) . '%'); } // Recursively Delete folder - DANGEROUS! USE WITH CARE!!!! - private function rrmdir($dir) { + private function rrmdir($dir) + { if (is_dir($dir)) { $objects = scandir($dir); foreach ($objects as $object) { if ($object != "." && $object != "..") { - if (filetype($dir . "/" . $object) == "dir") {$this->rrmdir($dir . "/" . $object); + if (filetype($dir . "/" . $object) == "dir") { + $this->rrmdir($dir . "/" . $object); } else { unlink($dir . "/" . $object); } @@ -225,6 +235,7 @@ class InstallCommand extends Command { reset($objects); rmdir($dir); + return true; } }