Implement version command and better help

This commit is contained in:
Niklas Keller
2016-03-28 12:26:17 +02:00
parent 8d085347b9
commit 866b172c5f
5 changed files with 226 additions and 60 deletions

View File

@@ -5,15 +5,19 @@ use Auryn\Injector;
use Kelunik\AcmeClient\AcmeFactory;
use League\CLImate\CLImate;
$logo = <<<LOGO
____ __________ ___ ___
/ __ `/ ___/ __ `__ \/ _ \
/ /_/ / /__/ / / / / / __/
\__,_/\___/_/ /_/ /_/\___/
LOGO;
if (!file_exists(__DIR__ . "/../vendor/autoload.php")) {
echo $logo;
echo <<<HELP
____ __________ ___ ___
/ __ `/ ___/ __ `__ \/ _ \
/ /_/ / /__/ / / / / / __/
\__,_/\___/_/ /_/ /_/\___/
You need to install the composer dependencies.
You need to install the composer dependencies.
composer install --no-dev
@@ -23,14 +27,10 @@ HELP;
}
if (!function_exists("openssl_pkey_get_private")) {
echo $logo;
echo <<<HELP
____ __________ ___ ___
/ __ `/ ___/ __ `__ \/ _ \
/ /_/ / /__/ / / / / / __/
\__,_/\___/_/ /_/ /_/\___/
You need to enable OpenSSL in your php.ini
You need to enable OpenSSL in your php.ini
HELP;
@@ -40,54 +40,55 @@ HELP;
require __DIR__ . "/../vendor/autoload.php";
$commands = [
"setup",
"issue",
"check",
"revoke",
"setup" => "Setup and register account.",
"issue" => "Issue a new certificate.",
"check" => "Check if a certificate is still valid long enough.",
"revoke" => "Revoke a certificate.",
"version" => "Print version information.",
];
$binary = \Kelunik\AcmeClient\getBinary();
$help = implode("\n ", array_map(function ($command) use ($binary) {
return "{$binary} {$command}";
}, $commands));
$help = implode(PHP_EOL, array_map(function ($command) use ($commands) {
$help = " <green>{$command}</green>\n";
$help .= " └─ {$commands[$command]}\n";
return $help;
}, array_keys($commands)));
$help = <<<EOT
____ __________ ___ ___
/ __ `/ ___/ __ `__ \/ _ \
/ /_/ / /__/ / / / / / __/
\__,_/\___/_/ /_/ /_/\___/
<yellow>Usage:</yellow>
bin/acme [command] [--args]
Usage: bin/acme command --args
Available Commands:
{$help}
Get more help by appending --help to specific commands.
<yellow>Options:</yellow>
<green>-h, --help</green>
└─ Print this help message.
<yellow>Available commands:</yellow>
{$help}
Get more help by appending <yellow>--help</yellow> to specific commands.
EOT;
$climate = new CLImate;
if (!in_array(PHP_SAPI, ["cli", "phpdbg"], true)) {
$climate->error("Please run this script via CLI!");
$climate->error("Please run this script on the command line!");
exit(1);
}
if (count($argv) === 1 || in_array($argv[1], ["h", "-h", "help", "--help"], true)) {
$climate->out($help);
$climate->out($logo . $help);
exit(0);
}
if (!in_array($argv[1], $commands)) {
$climate->br()->error(" Unknown command '{$argv[1]}'. Use --help for a list of available commands.");
if (!in_array($argv[1], array_keys($commands))) {
$climate->error("Unknown command '{$argv[1]}'. Use --help for a list of available commands.");
$suggestion = \Kelunik\AcmeClient\suggestCommand($argv[1], $commands);
$suggestion = \Kelunik\AcmeClient\suggestCommand($argv[1], array_keys($commands));
if ($suggestion) {
$climate->br()->out(" Did you mean '$suggestion'?");
$climate->br()->out(" Did you mean '$suggestion'?");
}
$climate->br();

View File

@@ -1,6 +1,6 @@
{
"name": "kelunik/acme-client",
"description": "Standalone PHP ACME client.",
"description": "Let's Encrypt / ACME client written in PHP for the CLI.",
"keywords": [
"ACME",
"letsencrypt",
@@ -24,7 +24,8 @@
"require-dev": {
"phpunit/phpunit": "^5",
"fabpot/php-cs-fixer": "^1.9",
"macfja/phar-builder": "dev-master#a2db582eab26ef7b15144c013408749a79fae361"
"macfja/phar-builder": "dev-master#97bfa5ffb2bb8beb26db2d5575e852dd10593ac3",
"league/event": "^2.1"
},
"license": "MIT",
"authors": [
@@ -48,8 +49,19 @@
"compression": "GZip",
"name": "acme-client.phar",
"output-dir": "build",
"include": ["src", "vendor/kelunik/acme/res", "vendor/amphp/socket/var"],
"entry-point": "bin/acme"
"include": ["info", "src", "vendor/kelunik/acme/res", "vendor/amphp/socket/var"],
"entry-point": "bin/acme",
"events": {
"build.before": [
"mkdir -p info",
"git describe --tags > info/build.version",
"php -r 'echo time();' > info/build.time"
],
"build.after": [
"rm -rf info",
"chmod +x build/acme-client.phar"
]
}
}
}
}

97
composer.lock generated
View File

@@ -4,8 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "3bfc6d13e53f6be6788859cbdd68b52a",
"content-hash": "62b8fb8281fc8a7b9925c115301f4707",
"hash": "e1091f4600ce5c211e5c11f89718d7cf",
"content-hash": "55e9166fdb7dfbdbda7ef9144e494cdd",
"packages": [
{
"name": "amphp/amp",
@@ -172,16 +172,16 @@
},
{
"name": "amphp/dns",
"version": "v0.8.9",
"version": "v0.8.10",
"source": {
"type": "git",
"url": "https://github.com/amphp/dns.git",
"reference": "78cda5692a80ec0a5b50ee7616d93426961836ec"
"reference": "9f12b2264f74e0cbad67565308f9e106fb6a5bec"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/amphp/dns/zipball/78cda5692a80ec0a5b50ee7616d93426961836ec",
"reference": "78cda5692a80ec0a5b50ee7616d93426961836ec",
"url": "https://api.github.com/repos/amphp/dns/zipball/9f12b2264f74e0cbad67565308f9e106fb6a5bec",
"reference": "9f12b2264f74e0cbad67565308f9e106fb6a5bec",
"shasum": ""
},
"require": {
@@ -236,7 +236,7 @@
"dns",
"resolve"
],
"time": "2016-03-24 19:17:04"
"time": "2016-03-26 20:35:44"
},
{
"name": "amphp/file",
@@ -1210,18 +1210,68 @@
"description": "A tool to automatically fix PHP code style",
"time": "2016-02-26 07:37:29"
},
{
"name": "league/event",
"version": "2.1.2",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/event.git",
"reference": "e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/event/zipball/e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd",
"reference": "e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd",
"shasum": ""
},
"require": {
"php": ">=5.4.0"
},
"require-dev": {
"henrikbjorn/phpspec-code-coverage": "~1.0.1",
"phpspec/phpspec": "~2.0.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
}
},
"autoload": {
"psr-4": {
"League\\Event\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Frank de Jonge",
"email": "info@frenky.net"
}
],
"description": "Event package",
"keywords": [
"emitter",
"event",
"listener"
],
"time": "2015-05-21 12:24:47"
},
{
"name": "macfja/phar-builder",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/MacFJA/PharBuilder.git",
"reference": "a2db582eab26ef7b15144c013408749a79fae361"
"reference": "97bfa5ffb2bb8beb26db2d5575e852dd10593ac3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/MacFJA/PharBuilder/zipball/9396c639ca105f4c07649fbc15200297e8981764",
"reference": "a2db582eab26ef7b15144c013408749a79fae361",
"url": "https://api.github.com/repos/MacFJA/PharBuilder/zipball/8a2d96e9497418729d00df1e86a1778f8a9f3268",
"reference": "97bfa5ffb2bb8beb26db2d5575e852dd10593ac3",
"shasum": ""
},
"require": {
@@ -1230,6 +1280,11 @@
"symfony/console": "~2.6",
"webignition/readable-duration": "~0"
},
"require-dev": {
"phpmd/phpmd": "^2.4",
"sebastian/phpcpd": "^2.0",
"squizlabs/php_codesniffer": "^2.5"
},
"bin": [
"bin/phar-builder",
"bin/phar-builder.php"
@@ -1261,7 +1316,7 @@
}
],
"description": "CLI tool for create phar of your composer based project",
"time": "2016-03-24 00:08:01"
"time": "2016-03-27 12:42:09"
},
{
"name": "macfja/symfony-console-filechooser",
@@ -2346,16 +2401,16 @@
},
{
"name": "symfony/console",
"version": "v2.8.3",
"version": "v2.8.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "56cc5caf051189720b8de974e4746090aaa10d44"
"reference": "9a5aef5fc0d4eff86853d44202b02be8d5a20154"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/56cc5caf051189720b8de974e4746090aaa10d44",
"reference": "56cc5caf051189720b8de974e4746090aaa10d44",
"url": "https://api.github.com/repos/symfony/console/zipball/9a5aef5fc0d4eff86853d44202b02be8d5a20154",
"reference": "9a5aef5fc0d4eff86853d44202b02be8d5a20154",
"shasum": ""
},
"require": {
@@ -2402,7 +2457,7 @@
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"time": "2016-02-28 16:20:50"
"time": "2016-03-17 09:19:04"
},
{
"name": "symfony/event-dispatcher",
@@ -2515,16 +2570,16 @@
},
{
"name": "symfony/finder",
"version": "v2.8.3",
"version": "v2.8.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "877bb4b16ea573cc8c024e9590888fcf7eb7e0f7"
"reference": "ca24cf2cd4e3826f571e0067e535758e73807aa1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/877bb4b16ea573cc8c024e9590888fcf7eb7e0f7",
"reference": "877bb4b16ea573cc8c024e9590888fcf7eb7e0f7",
"url": "https://api.github.com/repos/symfony/finder/zipball/ca24cf2cd4e3826f571e0067e535758e73807aa1",
"reference": "ca24cf2cd4e3826f571e0067e535758e73807aa1",
"shasum": ""
},
"require": {
@@ -2560,7 +2615,7 @@
],
"description": "Symfony Finder Component",
"homepage": "https://symfony.com",
"time": "2016-02-22 16:12:45"
"time": "2016-03-10 10:53:53"
},
{
"name": "symfony/polyfill-mbstring",

76
src/Commands/Version.php Normal file
View File

@@ -0,0 +1,76 @@
<?php
namespace Kelunik\AcmeClient\Commands;
use League\CLImate\Argument\Manager;
use League\CLImate\CLImate;
use RuntimeException;
class Version implements Command {
private $climate;
public function __construct(CLImate $climate) {
$this->climate = $climate;
}
public function execute(Manager $args) {
$version = $this->getVersion();
$buildTime = $this->readFileOr("info/build.time", time());
$buildDate = date('M jS Y H:i:s T', (int) trim($buildTime));
$package = json_decode($this->readFileOr("composer.json", new RuntimeException("No composer.json found.")));
$this->climate->out("┌ <green>kelunik/acme-client</green> @ <yellow>{$version}</yellow> (built: {$buildDate})");
$this->climate->out(($args->defined("deps") ? "" : "") . " " . $this->getDescription($package));
if ($args->defined("deps")) {
$lockFile = json_decode($this->readFileOr("composer.lock", new RuntimeException("No composer.lock found.")));
$packages = $lockFile->packages;
for ($i = 0; $i < count($packages); $i++) {
$link = $i === count($packages) - 1 ? "└──" : "├──";
$this->climate->out("{$link} <green>{$packages[$i]->name}</green> @ <yellow>{$packages[$i]->version}</yellow>");
$link = $i === count($packages) - 1 ? " " : "";
$this->climate->out("{$link} " . $this->getDescription($packages[$i]));
}
}
}
private function getDescription($package) {
return \Kelunik\AcmeClient\ellipsis(isset($package->description) ? $package->description : "");
}
private function getVersion() {
if (file_exists(__DIR__ . "/../../.git")) {
$version = `git describe --tags`;
} else {
$version = $this->readFileOr("info/build.version", "-unknown");
}
return substr(trim($version), 1);
}
private function readFileOr($file, $default = "") {
if (file_exists(__DIR__ . "/../../" . $file)) {
return file_get_contents(__DIR__ . "/../../" . $file);
} else {
if ($default instanceof \Exception || $default instanceof \Throwable) {
throw $default;
}
return $default;
}
}
public static function getDefinition() {
return [
"deps" => [
"longPrefix" => "deps",
"description" => "Show also the bundled dependency versions.",
"noValue" => true,
],
];
}
}

View File

@@ -218,4 +218,26 @@ function getBinary() {
}
return $binary;
}
/**
* Cuts a text to a certain length and appends an ellipsis if necessary.
*
* @param string $text text to shorten
* @param int $max maximum length
* @param string $append appendix when too long
* @return string shortened string
*/
function ellipsis($text, $max = 70, $append = "") {
if (strlen($text) <= $max) {
return $text;
}
$out = substr($text, 0, $max);
if (strpos($text, " ") === false) {
return $out . $append;
}
return preg_replace("/\\w+$/", "", $out) . $append;
}