diff --git a/bin/gpm b/bin/gpm index 3e9374702..b811b0be1 100755 --- a/bin/gpm +++ b/bin/gpm @@ -35,5 +35,6 @@ $app->addCommands(array( new \Grav\Console\Gpm\InfoCommand(), new \Grav\Console\Gpm\InstallCommand(), new \Grav\Console\Gpm\UpdateCommand(), + new \Grav\Console\Gpm\SelfupgradeCommand(), )); $app->run(); diff --git a/system/src/Grav/Console/Gpm/SelfupgradeCommand.php b/system/src/Grav/Console/Gpm/SelfupgradeCommand.php new file mode 100644 index 000000000..0a05914da --- /dev/null +++ b/system/src/Grav/Console/Gpm/SelfupgradeCommand.php @@ -0,0 +1,122 @@ +setName("self-upgrade") + ->setAliases(['selfupgrade']) + ->addOption( + 'force', + 'f', + InputOption::VALUE_NONE, + 'Force re-fetching the data from remote' + ) + ->setDescription("Detects and performs an update of plugins and themes when available") + ->setHelp('The update command updates plugins and themes when a new version is available'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->setupConsole($input, $output); + $this->upgrader = new Upgrader($this->input->getOption('force')); + + $local = $this->upgrader->getLocalVersion(); + $remote = $this->upgrader->getRemoteVersion(); + $update = $this->upgrader->getAssets()->{'grav-update'}; + $release = strftime('%c', strtotime($this->upgrader->getReleaseDate())); + + if (!$this->upgrader->isUpgradable()) { + $this->output->writeln("You are already running the latest version of Grav (v" . $local . ") released on " . $release); + exit; + } + + $this->output->writeln("Preparing to upgrade Grav to v" . $remote . " [release date: " . $release . "]"); + + $this->output->write(" |- Downloading upgrade [" . $this->formatBytes($update->size) . "]... 0%"); + $this->file = $this->download($update); + + $this->output->write(" |- Installing upgrade... "); + $installation = $this->upgrade(); + + if (!$installation) { + $this->output->writeln(" '- Installation failed or aborted."); + $this->output->writeln(''); + } else { + $this->output->writeln(" '- Success! "); + $this->output->writeln(''); + } + } + + private function download($package) + { + $this->tmp = sys_get_temp_dir() . DS . 'Grav-' . uniqid(); + $output = Response::get($package->download, [], [$this, 'progress']); + + Folder::mkdir($this->tmp); + + $this->output->write("\x0D"); + $this->output->write(" |- Downloading upgrade [" . $this->formatBytes($package->size) . "]... 100%"); + $this->output->writeln(''); + + file_put_contents($this->tmp . DS . $package->name, $output); + + return $this->tmp . DS . $package->name; + } + + private function upgrade() + { + $installer = Installer::install($this->file, GRAV_ROOT, ['sophisticated' => true, 'overwrite' => true, 'ignore_symlinks' => true]); + $errorCode = Installer::lastErrorCode(); + Folder::delete($this->tmp); + + 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 upgrade... error "); + $this->output->writeln(" | '- " . $installer->lastErrorMsg()); + + return false; + } + + $this->output->write("\x0D"); + // extra white spaces to clear out the buffer properly + $this->output->writeln(" |- Installing upgrade... ok "); + + return true; + } + + public function progress($progress) + { + $this->output->write("\x0D"); + $this->output->write(" |- Downloading upgrade [" . $this->formatBytes($progress["filesize"]) . "]... " . str_pad($progress['percent'], 5, " ", STR_PAD_LEFT) . '%'); + } + + public function formatBytes($size, $precision = 2) + { + $base = log($size) / log(1024); + $suffixes = array('', 'k', 'M', 'G', 'T'); + + return round(pow(1024, $base - floor($base)), $precision) . $suffixes[floor($base)]; + } +}