Skip to content

Commit

Permalink
Merge pull request #2290 from CachetHQ/console-install
Browse files Browse the repository at this point in the history
✨ Add cachet:install command
  • Loading branch information
jbrooksuk committed Jan 2, 2017
2 parents 3240396 + 186cbcf commit 0b7c787
Show file tree
Hide file tree
Showing 2 changed files with 371 additions and 0 deletions.
369 changes: 369 additions & 0 deletions app/Console/Commands/InstallCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,369 @@
<?php

/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace CachetHQ\Cachet\Console\Commands;

use Dotenv\Dotenv;
use Dotenv\Exception\InvalidPathException;
use Illuminate\Console\Command;

/**
* This is the install command class.
*
* @author James Brooks <[email protected]>
*/
class InstallCommand extends Command
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'cachet:install';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Install Cachet';

/**
* Execute the console command.
*
* @return void
*/
public function fire()
{
if (!$this->confirm('Do you want to install Cachet?')) {
$this->line('Installation aborted. Goodbye!');

return;
}

$this->configureEnvironmentFile();
$this->configureKey();
$this->configureDatabase();
$this->configureDrivers();
$this->configureMail();
$this->configureCachet();

$this->info('Cachet is installed ⚡');
}

/**
* Copy the environment file.
*
* @return void
*/
protected function configureEnvironmentFile()
{
$dir = app()->environmentPath();
$file = app()->environmentFile();
$path = "{$dir}/{$file}";

if (file_exists($path)) {
$this->line('Environment file already exists. Moving on.');

return;
}

copy("$path.example", $path);
}

/**
* Generate the app key.
*
* @return void
*/
protected function configureKey()
{
$this->call('key:generate');
}

/**
* Configure the database.
*
* @param array $default
*
* @return void
*/
protected function configureDatabase(array $default = [])
{
$config = array_merge([
'DB_DRIVER' => null,
'DB_HOST' => null,
'DB_DATABASE' => null,
'DB_USERNAME' => null,
'DB_PASSWORD' => null,
'DB_PORT' => null,
'DB_PREFIX' => null,
], $default);

$config['DB_DRIVER'] = $this->choice('Which database driver do you want to use?', [
'mysql' => 'MySQL',
'postgresql' => 'PostgreSQL',
'sqlite' => 'SQLite',
], $config['DB_DRIVER']);

if ($config['DB_DRIVER'] === 'sqlite') {
$config['DB_DATABASE'] = $this->ask('Please provide the full path to your SQLite file.', $config['DB_DATABASE']);
} else {
$config['DB_HOST'] = $this->ask("What is the host of your {$config['DB_DRIVER']} database?", $config['DB_HOST']);

$config['DB_DATABASE'] = $this->ask('What is the name of the database that Cachet should use?', $config['DB_DATABASE']);

$config['DB_USERNAME'] = $this->ask('What username should we connect with?', $config['DB_USERNAME']);

$config['DB_PASSWORD'] = $this->secret('What password should we connect with?', $config['DB_PASSWORD']);

if ($this->confirm('Is your database listening on a non-standard port number?')) {
$config['DB_PORT'] = $this->anticipate('What port number is your database using?', [3306, 5432], $config['DB_PORT']);
}
}

if ($this->confirm('Do you want to use a prefix on the table names?')) {
$config['DB_PREFIX'] = $this->ask('Please enter the prefix now...', $config['DB_PREFIX']);
}

// Format the settings ready to display them in the table.
$this->formatConfigsTable($config);

if (!$this->confirm('Are these settings correct?')) {
return $this->configureDatabase($config);
}

foreach ($config as $setting => $value) {
$this->writeEnv($setting, $value);
}
}

/**
* Configure other drivers.
*
* @param array $default
*
* @return void
*/
protected function configureDrivers(array $default = [])
{
$config = array_merge([
'CACHE_DRIVER' => null,
'SESSION_DRIVER' => null,
'QUEUE_DRIVER' => null,
], $default);

// Format the settings ready to display them in the table.
$this->formatConfigsTable($config);

$config['CACHE_DRIVER'] = $this->choice('Which cache driver do you want to use?', [
'apc' => 'APC(u)',
'array' => 'Array',
'database' => 'Database',
'file' => 'File',
'memcached' => 'Memcached',
'redis' => 'Redis',
], $config['CACHE_DRIVER']);

// We need to configure Redis.
if ($config['CACHE_DRIVER'] === 'redis') {
$this->configureRedis();
}

$config['SESSION_DRIVER'] = $this->choice('Which session driver do you want to use?', [
'apc' => 'APC(u)',
'array' => 'Array',
'database' => 'Database',
'file' => 'File',
'memcached' => 'Memcached',
'redis' => 'Redis',
], $config['SESSION_DRIVER']);

// We need to configure Redis.
if ($config['SESSION_DRIVER'] === 'redis') {
$this->configureRedis();
}

$config['QUEUE_DRIVER'] = $this->choice('Which queue driver do you want to use?', [
'null' => 'None',
'sync' => 'Synchronous',
'database' => 'Database',
'beanstalkd' => 'Beanstalk',
'sqs' => 'Amazon SQS',
'redis' => 'Redis',
], $config['QUEUE_DRIVER']);

// We need to configure Redis, but only if the cache driver wasn't redis.
if ($config['QUEUE_DRIVER'] === 'redis' && ($config['SESSION_DRIVER'] !== 'redis' || $config['CACHE_DRIVER'] !== 'redis')) {
$this->configureRedis();
}

// Format the settings ready to display them in the table.
$this->formatConfigsTable($config);

if (!$this->confirm('Are these settings correct?')) {
return $this->configureDrivers($config);
}

foreach ($config as $setting => $value) {
$this->writeEnv($setting, $value);
}
}

/**
* Configure mail.
*
* @param array $config
*
* @return void
*/
protected function configureMail(array $config = [])
{
$config = array_merge([
'MAIL_DRIVER' => null,
'MAIL_HOST' => null,
'MAIL_PORT' => null,
'MAIL_USERNAME' => null,
'MAIL_PASSWORD' => null,
'MAIL_ADDRESS' => null,
'MAIL_NAME' => null,
'MAIL_ENCRYPTION' => null,
], $config);

// Don't continue with these settings if we're not interested in notifications.
if (!$this->confirm('Do you want Cachet to send mail notifications?')) {
return;
}

$config['MAIL_DRIVER'] = $this->choice('What driver do you want to use to send notifications?', [
'smtp' => 'SMTP',
'mail' => 'Mail',
'sendmail' => 'Sendmail',
'mailgun' => 'Mailgun',
'mandrill' => 'Mandrill',
'ses' => 'Amazon SES',
'sparkpost' => 'SparkPost',
'log' => 'Log (Testing)',
]);

if (!$config['MAIL_DRIVER'] === 'log') {
if ($config['MAIL_DRIVER'] === 'smtp') {
$config['MAIL_HOST'] = $this->ask('Please supply your mail server host');
}

$config['MAIL_ADDRESS'] = $this->ask('What email address should we send notifications from?');
$config['MAIL_USERNAME'] = $this->ask('What username should we connect as?');
$config['MAIL_PASSWORD'] = $this->secret('What password should we connect with?');
}

// Format the settings ready to display them in the table.
$this->formatConfigsTable($config);

if (!$this->confirm('Are these settings correct?')) {
return $this->configureMail($config);
}

foreach ($config as $setting => $value) {
$this->writeEnv($setting, $value);
}
}

/**
* Configure Cachet.
*
* @return void
*/
protected function configureCachet()
{
if ($this->confirm('Do you wish to use Cachet Beacon?')) {
$config['CACHET_BEACON'] = 'true';
}

if ($this->confirm('Do you wish to use Emoji? This requires a GitHub oAuth Token!')) {
$config['GITHUB_TOKEN'] = $this->ask('Please enter your GitHub oAuth Token');
$config['CACHET_EMOJI'] = 'true';
}

foreach ($config as $setting => $value) {
$this->writeEnv($setting, $value);
}
}

/**
* Configure the redis connection.
*
* @return void
*/
protected function configureRedis()
{
$config = [
'REDIS_HOST' => null,
'REDIS_DATABASE' => null,
'REDIS_PORT' => null,
];

$config['REDIS_HOST'] = $this->ask('What is the host of your redis server?');
$config['REDIS_DATABASE'] = $this->ask('What is the name of the database that Cachet should use?');
$config['REDIS_PORT'] = $this->ask('What port should Cachet use?', 6379);

foreach ($config as $setting => $value) {
$this->writeEnv($setting, $value);
}
}

/**
* Format the configs into a pretty table that we can easily read.
*
* @param array $config
*
* @return void
*/
protected function formatConfigsTable(array $config)
{
$configRows = [];

foreach ($config as $setting => $value) {
$configRows[] = compact('setting', 'value');
}

$this->table(['Setting', 'Value'], $configRows);
}

/**
* Writes to the .env file with given parameters.
*
* @param string $key
* @param mixed $value
*
* @return void
*/
protected function writeEnv($key, $value)
{
$dir = app()->environmentPath();
$file = app()->environmentFile();
$path = "{$dir}/{$file}";

try {
(new Dotenv($dir, $file))->load();

$envKey = strtoupper($key);
$envValue = env($envKey) ?: 'null';

file_put_contents($path, str_replace(
"{$envKey}={$envValue}",
"{$envKey}={$value}",
file_get_contents($path)
));
} catch (InvalidPathException $e) {
throw $e;
}
}
}
2 changes: 2 additions & 0 deletions app/Console/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use CachetHQ\Cachet\Console\Commands\BeaconCommand;
use CachetHQ\Cachet\Console\Commands\DemoMetricPointSeederCommand;
use CachetHQ\Cachet\Console\Commands\DemoSeederCommand;
use CachetHQ\Cachet\Console\Commands\InstallCommand;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;

Expand All @@ -35,6 +36,7 @@ class Kernel extends ConsoleKernel
BeaconCommand::class,
DemoMetricPointSeederCommand::class,
DemoSeederCommand::class,
InstallCommand::class,
];

/**
Expand Down

0 comments on commit 0b7c787

Please sign in to comment.