* Dariusz Rumiński * * This source file is subject to the MIT license that is bundled * with this source code in the file LICENSE. */ namespace PhpCsFixer\Console\Command; use PhpCsFixer\Console\SelfUpdate\NewVersionCheckerInterface; use PhpCsFixer\PharCheckerInterface; use PhpCsFixer\Preg; use PhpCsFixer\ToolInfoInterface; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Console\Output\OutputInterface; /** * @author Igor Wiedler * @author Stephane PY * @author Grégoire Pineau * @author Dariusz Rumiński * * @internal */ final class SelfUpdateCommand extends Command { /** * @var string */ protected static $defaultName = 'self-update'; /** * @var NewVersionCheckerInterface */ private $versionChecker; /** * @var ToolInfoInterface */ private $toolInfo; /** * @var PharCheckerInterface */ private $pharChecker; public function __construct( NewVersionCheckerInterface $versionChecker, ToolInfoInterface $toolInfo, PharCheckerInterface $pharChecker ) { parent::__construct(); $this->versionChecker = $versionChecker; $this->toolInfo = $toolInfo; $this->pharChecker = $pharChecker; } /** * {@inheritdoc} */ protected function configure(): void { $this ->setAliases(['selfupdate']) ->setDefinition( [ new InputOption('--force', '-f', InputOption::VALUE_NONE, 'Force update to next major version if available.'), ] ) ->setDescription('Update php-cs-fixer.phar to the latest stable version.') ->setHelp( <<<'EOT' The %command.name% command replace your php-cs-fixer.phar by the latest version released on: https://github.com/FriendsOfPHP/PHP-CS-Fixer/releases $ php php-cs-fixer.phar %command.name% EOT ) ; } /** * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output): int { if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity() && $output instanceof ConsoleOutputInterface) { $stdErr = $output->getErrorOutput(); $stdErr->writeln($this->getApplication()->getLongVersion()); $stdErr->writeln(sprintf('Runtime: PHP %s', PHP_VERSION)); } if (!$this->toolInfo->isInstalledAsPhar()) { $output->writeln('Self-update is available only for PHAR version.'); return 1; } $currentVersion = $this->getApplication()->getVersion(); Preg::match('/^v?(?\d+)\./', $currentVersion, $matches); $currentMajor = (int) $matches['major']; try { $latestVersion = $this->versionChecker->getLatestVersion(); $latestVersionOfCurrentMajor = $this->versionChecker->getLatestVersionOfMajor($currentMajor); } catch (\Exception $exception) { $output->writeln(sprintf( 'Unable to determine newest version: %s', $exception->getMessage() )); return 1; } if (1 !== $this->versionChecker->compareVersions($latestVersion, $currentVersion)) { $output->writeln('PHP CS Fixer is already up-to-date.'); return 0; } $remoteTag = $latestVersion; if ( 0 !== $this->versionChecker->compareVersions($latestVersionOfCurrentMajor, $latestVersion) && true !== $input->getOption('force') ) { $output->writeln(sprintf('A new major version of PHP CS Fixer is available (%s)', $latestVersion)); $output->writeln(sprintf('Before upgrading please read https://github.com/FriendsOfPHP/PHP-CS-Fixer/blob/%s/UPGRADE-v%s.md', $latestVersion, $currentMajor + 1)); $output->writeln('If you are ready to upgrade run this command with -f'); $output->writeln('Checking for new minor/patch version...'); if (1 !== $this->versionChecker->compareVersions($latestVersionOfCurrentMajor, $currentVersion)) { $output->writeln('No minor update for PHP CS Fixer.'); return 0; } $remoteTag = $latestVersionOfCurrentMajor; } $localFilename = realpath($_SERVER['argv'][0]) ?: $_SERVER['argv'][0]; if (!is_writable($localFilename)) { $output->writeln(sprintf('No permission to update "%s" file.', $localFilename)); return 1; } $tempFilename = \dirname($localFilename).'/'.basename($localFilename, '.phar').'-tmp.phar'; $remoteFilename = $this->toolInfo->getPharDownloadUri($remoteTag); if (false === @copy($remoteFilename, $tempFilename)) { $output->writeln(sprintf('Unable to download new version %s from the server.', $remoteTag)); return 1; } chmod($tempFilename, 0777 & ~umask()); $pharInvalidityReason = $this->pharChecker->checkFileValidity($tempFilename); if (null !== $pharInvalidityReason) { unlink($tempFilename); $output->writeln(sprintf('The download of %s is corrupt (%s).', $remoteTag, $pharInvalidityReason)); $output->writeln('Please re-run the "self-update" command to try again.'); return 1; } rename($tempFilename, $localFilename); $output->writeln(sprintf('PHP CS Fixer updated (%s -> %s)', $currentVersion, $remoteTag)); return 0; } }