diff --git a/bin/phpmnd b/bin/phpmnd
index e4d3d9e..afd74f8 100755
--- a/bin/phpmnd
+++ b/bin/phpmnd
@@ -37,4 +37,28 @@ if (false === $loaded) {
ini_set('xdebug.max_nesting_level', 10000);
$application = new Povils\PHPMND\Console\Application;
-$application->run();
+$application->add(new Povils\PHPMND\Console\Command);
+if ('phar:' === substr(__FILE__, 0, 5)) {
+ $application->add(new Povils\PHPMND\Console\Command\SelfUpdate);
+}
+
+$output = new Symfony\Component\Console\Output\ConsoleOutput();
+$input = new \Symfony\Component\Console\Input\ArgvInput(prepareArgv());
+$application->run($input, $output);
+
+function prepareArgv()
+{
+ $argv = $_SERVER['argv'];
+
+ $found = false;
+
+ if (isset($argv[1]) && ('run' === $argv[1] || 'self-update' === $argv[1])) {
+ $found = true;
+ }
+
+ if (!$found) {
+ array_splice($argv, 1, 0, ['run']);
+ }
+
+ return $argv;
+}
diff --git a/box.json.dist b/box.json.dist
index 173eeb9..85be828 100644
--- a/box.json.dist
+++ b/box.json.dist
@@ -40,7 +40,8 @@
"phar-io/manifest",
"phar-io/version",
"theseer/tokenizer",
- "sebastian/object-reflector"
+ "sebastian/object-reflector",
+ "squizlabs/php_codesniffer"
],
"in": [
"vendor"
diff --git a/composer.json b/composer.json
index 57d698e..2d098e3 100644
--- a/composer.json
+++ b/composer.json
@@ -22,7 +22,8 @@
},
"require-dev": {
"phpunit/phpunit": "^5.7 || ^6.0",
- "squizlabs/php_codesniffer": "^2.8.1"
+ "squizlabs/php_codesniffer": "^2.8.1",
+ "padraic/phar-updater": "^1.0.3"
},
"autoload": {
"psr-4": {
diff --git a/src/Console/Application.php b/src/Console/Application.php
index 8a50101..3a94890 100644
--- a/src/Console/Application.php
+++ b/src/Console/Application.php
@@ -16,40 +16,11 @@ class Application extends BaseApplication
{
const VERSION = '1.1.0';
const COMMAND_NAME = 'phpmnd';
+ const PACKAGIST_PACKAGE_NAME = 'povils/phpmnd';
public function __construct()
{
- parent::__construct('phpmnd', self::VERSION);
- }
-
- /**
- * @inheritdoc
- */
- protected function getCommandName(InputInterface $input)
- {
- return self::COMMAND_NAME;
- }
-
- /**
- * @inheritdoc
- */
- protected function getDefaultCommands()
- {
- $defaultCommands = parent::getDefaultCommands();
- $defaultCommands[] = new Command;
-
- return $defaultCommands;
- }
-
- /**
- * @inheritdoc
- */
- public function getDefinition()
- {
- $inputDefinition = parent::getDefinition();
- $inputDefinition->setArguments();
-
- return $inputDefinition;
+ parent::__construct(self::COMMAND_NAME, self::VERSION);
}
/**
@@ -70,8 +41,8 @@ public function doRun(InputInterface $input, OutputInterface $output)
exit;
}
- if (null === $input->getFirstArgument()) {
- $input = new ArrayInput(['--help']);
+ if ('run' === (string) $input) {
+ $input = new ArrayInput(['run','--help']);
}
return parent::doRun($input, $output);
diff --git a/src/Console/Command.php b/src/Console/Command.php
index 6aa3842..7fec06a 100644
--- a/src/Console/Command.php
+++ b/src/Console/Command.php
@@ -31,7 +31,8 @@ class Command extends BaseCommand
protected function configure()
{
$this
- ->setName('phpmnd')
+ ->setName('run')
+ ->setDescription('Runs PHPMND. Executed by default when no other command provided.')
->setDefinition(
[
new InputArgument(
diff --git a/src/Console/Command/SelfUpdate.php b/src/Console/Command/SelfUpdate.php
new file mode 100644
index 0000000..844d9d0
--- /dev/null
+++ b/src/Console/Command/SelfUpdate.php
@@ -0,0 +1,209 @@
+setName('self-update')
+ ->setDescription('Update phpmnd.phar to most recent stable build.')
+ ->addOption(
+ 'rollback',
+ 'r',
+ InputOption::VALUE_NONE,
+ 'Rollback to previous version of PHPMND if available on filesystem.'
+ )
+ ->addOption(
+ 'check',
+ 'c',
+ InputOption::VALUE_NONE,
+ 'Checks whether an update is available.'
+ )
+ ;
+ }
+
+ /**
+ * Execute the command.
+ *
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $this->output = $output;
+ $this->version = $this->getApplication()->getVersion();
+
+ /**
+ * Check for ancilliary options
+ */
+ if ($input->getOption('rollback')) {
+ $this->rollback();
+ return;
+ }
+
+ if ($input->getOption('check')) {
+ $this->printAvailableUpdates();
+ return;
+ }
+
+ $this->updateToStableBuild();
+ }
+
+ /**
+ * Perform update using phar-updater configured for stable versions.
+ */
+ private function updateToStableBuild()
+ {
+ $this->update($this->getStableUpdater());
+ }
+
+ /**
+ * Get phar-updater instance.
+ */
+ private function getStableUpdater()
+ {
+ $updater = new Updater(null, false);
+ $updater->setStrategy(Updater::STRATEGY_GITHUB);
+ return $this->getGithubReleasesUpdater($updater);
+ }
+
+ /**
+ * Perform in-place update of phar.
+ */
+ private function update(Updater $updater)
+ {
+ $this->output->writeln('Updating...'.PHP_EOL);
+ try {
+ $result = $updater->update();
+
+ $newVersion = $updater->getNewVersion();
+ $oldVersion = $updater->getOldVersion();
+
+ if ($result) {
+ $this->output->writeln('PHPMND has been updated.');
+ $this->output->writeln(sprintf(
+ 'Current version is: %s.',
+ $newVersion
+ ));
+ $this->output->writeln(sprintf(
+ 'Previous version was: %s.',
+ $oldVersion
+ ));
+ } else {
+ $this->output->writeln('PHPMND is currently up to date.');
+ $this->output->writeln(sprintf(
+ 'Current version is: %s.',
+ $oldVersion
+ ));
+ }
+ } catch (\Exception $e) {
+ $this->output->writeln(sprintf('Error: %s', $e->getMessage()));
+ }
+ $this->output->write(PHP_EOL);
+ }
+
+ /**
+ * Attempt to rollback to the previous phar version.
+ */
+ private function rollback()
+ {
+ $updater = new Updater(null, false);
+ try {
+ $result = $updater->rollback();
+ if ($result) {
+ $this->output->writeln('PHPMND has been rolled back to prior version.');
+ } else {
+ $this->output->writeln('Rollback failed for reasons unknown.');
+ }
+ } catch (\Exception $e) {
+ $this->output->writeln(sprintf('Error: %s', $e->getMessage()));
+ }
+ }
+
+ private function printAvailableUpdates()
+ {
+ $this->printCurrentLocalVersion();
+ $this->printCurrentStableVersion();
+ }
+
+ /**
+ * Print the current version of the phar in use.
+ */
+ private function printCurrentLocalVersion()
+ {
+ $this->output->writeln(sprintf(
+ 'Your current local build version is: %s',
+ $this->version
+ ));
+ }
+
+ /**
+ * Send updater to version printer.
+ */
+ private function printCurrentStableVersion()
+ {
+ $this->printVersion($this->getStableUpdater());
+ }
+
+ /**
+ * Print a remotely available version.
+ * @param Updater $updater
+ */
+ private function printVersion(Updater $updater)
+ {
+ $stability = 'stable';
+ try {
+ if ($updater->hasUpdate()) {
+ $this->output->writeln(sprintf(
+ 'The current %s build available remotely is: %s',
+ $stability,
+ $updater->getNewVersion()
+ ));
+ } elseif (false == $updater->getNewVersion()) {
+ $this->output->writeln(sprintf('There are no new %s builds available.', $stability));
+ } else {
+ $this->output->writeln(sprintf('You have the current %s build installed.', $stability));
+ }
+ } catch (\Exception $e) {
+ $this->output->writeln(sprintf('Error: %s', $e->getMessage()));
+ }
+ }
+
+ /**
+ * @param Updater $updater
+ * @return Updater
+ */
+ private function getGithubReleasesUpdater(Updater $updater)
+ {
+ $updater->getStrategy()->setPackageName(Application::PACKAGIST_PACKAGE_NAME);
+ $updater->getStrategy()->setPharName(self::REMOTE_FILENAME);
+ $updater->getStrategy()->setCurrentLocalVersion($this->version);
+ return $updater;
+ }
+}