* * This source file is subject to the MIT license that is bundled * with this source code in the file LICENSE. */ namespace Symfony\CS\Console\Command; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\CS\ToolInfo; /** * @author Igor Wiedler * @author Stephane PY * @author Grégoire Pineau * @author Dariusz Rumiński */ class SelfUpdateCommand extends Command { /** * {@inheritdoc} */ protected function configure() { $this ->setName('self-update') ->setAliases(array('selfupdate')) ->setDescription('Update php-cs-fixer.phar to the latest version.') ->setHelp(<<%command.name% command replace your php-cs-fixer.phar by the latest version from cs.sensiolabs.org. php php-cs-fixer.phar %command.name% EOT ) ; } /** * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output) { if (!ToolInfo::isInstalledAsPhar()) { $output->writeln('Self-update is available only for PHAR version.'); return 1; } $currentVersion = explode('-', $this->getApplication()->getVersion()); $currentVersion = $currentVersion[0]; // ignore index #1 if exists (drop non-stable versions like `-DEV`) $currentVersion = explode('.', $currentVersion); if (!isset($currentVersion[2])) { $currentVersion[2] = 0; // fill patch version if missing } list($major, $minor, $patch) = $this->findBestVersion($currentVersion[0], $currentVersion[1], $currentVersion[2]); if ($this->getApplication()->getVersion() === $this->buildVersionString($major, $minor, $patch)) { $output->writeln('php-cs-fixer is already up to date.'); return; } $remoteFilename = $this->buildVersionFileUrl($major, $minor, $patch); $localFilename = $_SERVER['argv'][0]; $tempFilename = basename($localFilename, '.phar').'-tmp.phar'; if (false === @file_get_contents($remoteFilename)) { $output->writeln('Unable to download new versions from the server.'); return 1; } try { copy($remoteFilename, $tempFilename); chmod($tempFilename, 0777 & ~umask()); // test the phar validity $phar = new \Phar($tempFilename); // free the variable to unlock the file unset($phar); rename($tempFilename, $localFilename); $output->writeln('php-cs-fixer updated.'); } catch (\Exception $e) { if (!$e instanceof \UnexpectedValueException && !$e instanceof \PharException) { throw $e; } unlink($tempFilename); $output->writeln(sprintf('The download is corrupt (%s).', $e->getMessage())); $output->writeln('Please re-run the self-update command to try again.'); return 1; } } private function checkIfVersionFileExists($major, $minor, $patch) { $url = $this->buildVersionFileUrl($major, $minor, $patch); $headers = get_headers($url); return stripos($headers[0], '200 OK') ? true : false; } private function findBestVersion($major, $minor, $patch) { if ($this->checkIfVersionFileExists($major, $minor, $patch + 1)) { return $this->findBestVersion($major, $minor, $patch + 1); } if ($this->checkIfVersionFileExists($major, $minor + 1, 0)) { return $this->findBestVersion($major, $minor + 1, 0); } if ($this->checkIfVersionFileExists($major + 1, 0, 0)) { return $this->findBestVersion($major + 1, 0, 0); } return array($major, $minor, $patch); } private function buildVersionFileUrl($major, $minor, $patch) { return sprintf('http://get.sensiolabs.org/php-cs-fixer-v%s.phar', $this->buildVersionString($major, $minor, $patch)); } private function buildVersionString($major, $minor, $patch) { return sprintf('%d.%d.%d', $major, $minor, $patch); } }