setName('direct-install') ->setAliases(['directinstall']) ->addArgument( 'package-file', InputArgument::REQUIRED, 'Installable package local or remote . Can install specific version' ) ->addOption( '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 ) ->setDescription('Installs Grav, plugin, or theme directly from a file or a URL') ->setHelp('The direct-install command installs Grav, plugin, or theme directly from a file or a URL'); } /** * @return bool */ protected function serve() { // Making sure the destination is usable $this->destination = realpath($this->input->getOption('destination')); if ( !Installer::isGravInstance($this->destination) || !Installer::isValidDestination($this->destination, [Installer::EXISTS, Installer::IS_LINK]) ) { $this->output->writeln('ERROR: ' . Installer::lastErrorMsg()); exit; } $this->all_yes = $this->input->getOption('all-yes'); $package_file = $this->input->getArgument('package-file'); $helper = $this->getHelper('question'); $question = new ConfirmationQuestion("Are you sure you want to direct-install {$package_file} [y|N] ", false); $answer = $this->all_yes ? true : $helper->ask($this->input, $this->output, $question); if (!$answer) { $this->output->writeln('exiting...'); $this->output->writeln(''); exit; } $tmp_dir = Grav::instance()['locator']->findResource('tmp://', true, true); $tmp_zip = $tmp_dir . '/Grav-' . uniqid(); $this->output->writeln(''); $this->output->writeln("Preparing to install {$package_file}"); if (Response::isRemote($package_file)) { $this->output->write(' |- Downloading package... 0%'); try { $zip = GPM::downloadPackage($package_file, $tmp_zip); } catch (\RuntimeException $e) { $this->output->writeln(''); $this->output->writeln(" `- ERROR: {$e->getMessage()}"); $this->output->writeln(''); exit; } if ($zip) { $this->output->write("\x0D"); $this->output->write(' |- Downloading package... 100%'); $this->output->writeln(''); } } else { $this->output->write(' |- Copying package... 0%'); $zip = GPM::copyPackage($package_file, $tmp_zip); if ($zip) { $this->output->write("\x0D"); $this->output->write(' |- Copying package... 100%'); $this->output->writeln(''); } } if (file_exists($zip)) { $tmp_source = $tmp_dir . '/Grav-' . uniqid(); $this->output->write(' |- Extracting package... '); $extracted = Installer::unZip($zip, $tmp_source); if (!$extracted) { $this->output->write("\x0D"); $this->output->writeln(' |- Extracting package... failed'); Folder::delete($tmp_source); Folder::delete($tmp_zip); exit; } $this->output->write("\x0D"); $this->output->writeln(' |- Extracting package... ok'); $type = GPM::getPackageType($extracted); if (!$type) { $this->output->writeln(" '- ERROR: Not a valid Grav package"); $this->output->writeln(''); Folder::delete($tmp_source); Folder::delete($tmp_zip); exit; } $blueprint = GPM::getBlueprints($extracted); if ($blueprint) { if (isset($blueprint['dependencies'])) { $dependencies = []; foreach ($blueprint['dependencies'] as $dependency) { if (is_array($dependency)){ if (isset($dependency['name'])) { $dependencies[] = $dependency['name']; } if (isset($dependency['github'])) { $dependencies[] = $dependency['github']; } } else { $dependencies[] = $dependency; } } $this->output->writeln(' |- Dependencies found... [' . implode(',', $dependencies) . ']'); $question = new ConfirmationQuestion(" | '- Dependencies will not be satisfied. Continue ? [y|N] ", false); $answer = $this->all_yes ? true : $helper->ask($this->input, $this->output, $question); if (!$answer) { $this->output->writeln('exiting...'); $this->output->writeln(''); Folder::delete($tmp_source); Folder::delete($tmp_zip); exit; } } } if ($type === 'grav') { $this->output->write(' |- Checking destination... '); Installer::isValidDestination(GRAV_ROOT . '/system'); if (Installer::IS_LINK === Installer::lastErrorCode()) { $this->output->write("\x0D"); $this->output->writeln(' |- Checking destination... symbolic link'); $this->output->writeln(" '- ERROR: symlinks found... " . GRAV_ROOT . ''); $this->output->writeln(''); Folder::delete($tmp_source); Folder::delete($tmp_zip); exit; } $this->output->write("\x0D"); $this->output->writeln(' |- Checking destination... ok'); $this->output->write(' |- Installing package... '); static::upgradeGrav($zip, $extracted); } else { $name = GPM::getPackageName($extracted); if (!$name) { $this->output->writeln('ERROR: Name could not be determined. Please specify with --name|-n'); $this->output->writeln(''); Folder::delete($tmp_source); Folder::delete($tmp_zip); exit; } $install_path = GPM::getInstallPath($type, $name); $is_update = file_exists($install_path); $this->output->write(' |- Checking destination... '); Installer::isValidDestination(GRAV_ROOT . DS . $install_path); if (Installer::lastErrorCode() == Installer::IS_LINK) { $this->output->write("\x0D"); $this->output->writeln(' |- Checking destination... symbolic link'); $this->output->writeln(" '- ERROR: symlink found... " . GRAV_ROOT . DS . $install_path . ''); $this->output->writeln(''); Folder::delete($tmp_source); Folder::delete($tmp_zip); exit; } $this->output->write("\x0D"); $this->output->writeln(' |- Checking destination... ok'); $this->output->write(' |- Installing package... '); Installer::install( $zip, $this->destination, $options = [ 'install_path' => $install_path, 'theme' => (($type === 'theme')), 'is_update' => $is_update ], $extracted ); } Folder::delete($tmp_source); $this->output->write("\x0D"); if(Installer::lastErrorCode()) { $this->output->writeln(" '- " . Installer::lastErrorMsg() . ''); $this->output->writeln(''); } else { $this->output->writeln(' |- Installing package... ok'); $this->output->writeln(" '- Success! "); $this->output->writeln(''); } } else { $this->output->writeln(" '- ERROR: ZIP package could not be found"); } Folder::delete($tmp_zip); // clear cache after successful upgrade $this->clearCache(); return true; } private function upgradeGrav($zip, $folder, $keepFolder = false) { static $ignores = [ 'backup', 'cache', 'images', 'logs', 'tmp', 'user', '.htaccess', 'robots.txt' ]; if (!is_dir($folder)) { Installer::setError('Invalid source folder'); } try { $script = $folder . '/system/install.php'; /** Install $installer */ if ((file_exists($script) && $install = include $script) && is_callable($install)) { $install($zip); } else { Installer::install( $zip, GRAV_ROOT, ['sophisticated' => true, 'overwrite' => true, 'ignore_symlinks' => true, 'ignores' => $ignores], $folder, $keepFolder ); Cache::clearCache(); } } catch (\Exception $e) { Installer::setError($e->getMessage()); } } }