-
-
Notifications
You must be signed in to change notification settings - Fork 78
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a basic SelfUpdateCommand using phar-updater v1 #51
Changes from 18 commits
39793e0
9695621
6b8e784
45b5b2c
f93fd76
97c5af7
3f99e77
85c31cc
58b983c
f8b6573
ba29717
7a845e8
2d32a01
54abaaf
04e89ee
6623a86
72e113f
27d97ac
7251cb4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
/* | ||
* This file is part of the humbug/php-scoper package. | ||
* | ||
* Copyright (c) 2017 Théo FIDRY <[email protected]>, | ||
* Pádraic Brady <[email protected]> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Humbug\PhpScoper\Console\Command; | ||
|
||
use Humbug\PhpScoper\Logger\UpdateConsoleLogger; | ||
use Humbug\SelfUpdate\Updater; | ||
use Symfony\Component\Console\Command\Command; | ||
use Symfony\Component\Console\Input\InputInterface; | ||
use Symfony\Component\Console\Input\InputOption; | ||
use Symfony\Component\Console\Output\OutputInterface; | ||
use Symfony\Component\Console\Style\SymfonyStyle; | ||
|
||
final class SelfUpdateCommand extends Command | ||
{ | ||
/** @internal */ | ||
const REMOTE_FILENAME = 'php-scoper.phar'; | ||
/** @internal */ | ||
const STABILITY_STABLE = 'stable'; | ||
/** @internal */ | ||
const PACKAGIST_PACKAGE_NAME = 'humbug/php-scoper'; | ||
/** @internal */ | ||
const ROLLBACK_OPT = 'rollback'; | ||
/** @internal */ | ||
const CHECK_OPT = 'check'; | ||
|
||
/** | ||
* @var Updater | ||
*/ | ||
private $updater; | ||
|
||
/** | ||
* @var OutputInterface | ||
*/ | ||
private $output; | ||
|
||
/** | ||
* @var string | ||
*/ | ||
private $version; | ||
|
||
/** | ||
* @var UpdateConsoleLogger | ||
*/ | ||
private $logger; | ||
|
||
/** | ||
* @param Updater $updater | ||
*/ | ||
public function __construct(Updater $updater) | ||
{ | ||
parent::__construct(); | ||
|
||
$this->updater = $updater; | ||
} | ||
|
||
/** | ||
* @inheritdoc | ||
*/ | ||
protected function configure() | ||
{ | ||
$this | ||
->setName('self-update') | ||
->setDescription(sprintf( | ||
'Update %s to most recent stable build.', | ||
$this->getLocalPharName() | ||
)) | ||
->addOption( | ||
self::ROLLBACK_OPT, | ||
'r', | ||
InputOption::VALUE_NONE, | ||
'Rollback to previous version of PHP-Scoper if available on filesystem.' | ||
) | ||
->addOption( | ||
self::CHECK_OPT, | ||
'c', | ||
InputOption::VALUE_NONE, | ||
'Checks whether an update is available.' | ||
) | ||
; | ||
} | ||
|
||
/** | ||
* @inheritdoc | ||
*/ | ||
protected function execute(InputInterface $input, OutputInterface $output) | ||
{ | ||
$this->logger = new UpdateConsoleLogger( | ||
new SymfonyStyle($input, $output) | ||
); | ||
|
||
$this->output = $output; | ||
|
||
$this->version = $this->getApplication()->getVersion(); | ||
|
||
if ($input->getOption('rollback')) { | ||
$this->rollback(); | ||
|
||
return 0; | ||
} | ||
|
||
if ($input->getOption('check')) { | ||
$this->printAvailableUpdates(); | ||
|
||
return 0; | ||
} | ||
|
||
$this->update($this->createUpdater()); | ||
} | ||
|
||
private function createUpdater(): Updater | ||
{ | ||
$this->updater->setStrategy(Updater::STRATEGY_GITHUB); | ||
$this->updater->getStrategy()->setPackageName(self::PACKAGIST_PACKAGE_NAME); | ||
$this->updater->getStrategy()->setPharName(self::REMOTE_FILENAME); | ||
$this->updater->getStrategy()->setCurrentLocalVersion($this->version); | ||
|
||
return $this->updater; | ||
} | ||
|
||
private function update(Updater $updater) | ||
{ | ||
$this->logger->startUpdating(); | ||
try { | ||
$result = $this->updater->update(); | ||
|
||
$newVersion = $this->updater->getNewVersion(); | ||
$oldVersion = $this->updater->getOldVersion(); | ||
|
||
if ($result) { | ||
$this->logger->updateSuccess($newVersion, $oldVersion); | ||
} else { | ||
$this->logger->updateNotNeeded($oldVersion); | ||
} | ||
} catch (\Throwable $e) { | ||
$this->logger->error($e); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we're not failing here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mostly, it's just to add some preceding text to assure users the phar was not replaced. We could let the Throwable just fall through, but I always find that a bit untidy. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure about this though as we rule out any way for the user to know why it failed. I think throwing the throwable after logging the message would be fine |
||
throw $e; | ||
} | ||
} | ||
|
||
private function rollback() | ||
{ | ||
try { | ||
$result = $this->updater->rollback(); | ||
if ($result) { | ||
$this->logger->rollbackSuccess(); | ||
} else { | ||
$this->logger->rollbackFail(); | ||
} | ||
} catch (\Throwable $e) { | ||
$this->logger->error($e); | ||
throw $e; | ||
} | ||
} | ||
|
||
private function printAvailableUpdates() | ||
{ | ||
$this->logger->printLocalVersion($this->version); | ||
$this->printCurrentStableVersion(); | ||
} | ||
|
||
private function printCurrentStableVersion() | ||
{ | ||
$updater = $this->createUpdater(); | ||
$stability = self::STABILITY_STABLE; | ||
|
||
try { | ||
if ($updater->hasUpdate()) { | ||
$this->logger->printRemoteVersion( | ||
$stability, | ||
$updater->getNewVersion() | ||
); | ||
} elseif (false == $updater->getNewVersion()) { | ||
$this->logger->noNewRemoteVersions($stability); | ||
} else { | ||
$this->logger->currentVersionInstalled($stability); | ||
} | ||
} catch (\Throwable $e) { | ||
$this->logger->error($e); | ||
throw $e; | ||
} | ||
} | ||
|
||
private function getLocalPharName(): string | ||
{ | ||
return basename(\PHAR::running()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This command doesn't work without a PHAR, but can we ensure it fails gracefully? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you clarify? The SelfUpdateCommand only ever exists in a PHAR, so the above |
||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can this be done in the constructor?