diff --git a/composer.json b/composer.json index 187a473b..4156eae4 100644 --- a/composer.json +++ b/composer.json @@ -16,6 +16,7 @@ "require": { "php": "^7.3|^8.0", "illuminate/contracts": "^8.0|^9.0", + "illuminate/console": "^8.0|^9.0", "illuminate/support": "^8.0|^9.0" }, "bin": [ diff --git a/src/Console/InstallCommand.php b/src/Console/InstallCommand.php new file mode 100644 index 00000000..05c47091 --- /dev/null +++ b/src/Console/InstallCommand.php @@ -0,0 +1,107 @@ +choice('Which services would you like to install?', [ + 'mysql', + 'pgsql', + 'redis', + 'selenium', + 'mailhog', + 'meilisearch', + ], 0, null, true); + + $this->buildDockerCompose($services); + $this->replaceEnvVariables($services); + + $this->info('Sail scaffolding installed successfully.'); + } + + /** + * Build the Docker Compose file. + * + * @param array $services + * @return void + */ + protected function buildDockerCompose(array $services) + { + $depends = collect($services) + ->filter(function ($service) { + return in_array($service, ['mysql', 'pgsql', 'redis', 'selenium']); + })->map(function ($service) { + return " - {$service}"; + })->whenNotEmpty(function ($collection) { + return $collection->prepend('depends_on:'); + })->implode("\n"); + + $stubs = rtrim(collect($services)->map(function ($service) { + return file_get_contents(__DIR__ . "/../../stubs/{$service}.stub"); + })->implode('')); + + $volumes = collect($services) + ->filter(function ($service) { + return in_array($service, ['mysql', 'pgsql', 'redis', 'meilisearch']); + })->map(function ($service) { + return " sail{$service}:\n driver: local"; + })->whenNotEmpty(function ($collection) { + return $collection->prepend('volumes:'); + })->implode("\n"); + + $dockerCompose = file_get_contents(__DIR__ . '/../../stubs/docker-compose.stub'); + + $dockerCompose = str_replace('{{depends}}', $depends, $dockerCompose); + $dockerCompose = str_replace('{{services}}', $stubs, $dockerCompose); + $dockerCompose = str_replace('{{volumes}}', $volumes, $dockerCompose); + + file_put_contents($this->laravel->basePath('docker-compose.yml'), $dockerCompose); + } + + /** + * Replace the Host environment variables in the app's .env file. + * + * @param array $services + * @return void + */ + protected function replaceEnvVariables(array $services) + { + $environment = file_get_contents($this->laravel->basePath('.env')); + + $host = in_array('pgsql', $services) ? 'pgsql' : 'mysql'; + + $environment = str_replace('DB_HOST=127.0.0.1', "DB_HOST=$host", $environment); + $environment = str_replace('MEMCACHED_HOST=127.0.0.1', 'MEMCACHED_HOST=memcached', $environment); + $environment = str_replace('REDIS_HOST=127.0.0.1', 'REDIS_HOST=redis', $environment); + + if (in_array('meilisearch', $services)) { + $environment .= "\nSCOUT_DRIVER=meilisearch"; + $environment .= "\nMEILISEARCH_HOST=http://meilisearch:7700\n"; + } + + file_put_contents($this->laravel->basePath('.env'), $environment); + } +} diff --git a/src/Console/PublishCommand.php b/src/Console/PublishCommand.php new file mode 100644 index 00000000..fe09e8f1 --- /dev/null +++ b/src/Console/PublishCommand.php @@ -0,0 +1,38 @@ +call('vendor:publish', ['--tag' => 'sail']); + + file_put_contents($this->laravel->basePath('docker-compose.yml'), str_replace( + './vendor/laravel/sail/runtimes/8.0', + './docker/8.0', + file_get_contents($this->laravel->basePath('docker-compose.yml')) + )); + } +} diff --git a/src/SailServiceProvider.php b/src/SailServiceProvider.php index 734cd377..8aa9f8b3 100644 --- a/src/SailServiceProvider.php +++ b/src/SailServiceProvider.php @@ -3,8 +3,9 @@ namespace Laravel\Sail; use Illuminate\Contracts\Support\DeferrableProvider; -use Illuminate\Support\Facades\Artisan; use Illuminate\Support\ServiceProvider; +use Laravel\Sail\Console\InstallCommand; +use Laravel\Sail\Console\PublishCommand; class SailServiceProvider extends ServiceProvider implements DeferrableProvider { @@ -15,10 +16,8 @@ class SailServiceProvider extends ServiceProvider implements DeferrableProvider */ public function boot() { - if ($this->app->runningInConsole()) { - $this->registerCommands(); - $this->configurePublishing(); - } + $this->registerCommands(); + $this->configurePublishing(); } /** @@ -28,29 +27,12 @@ public function boot() */ protected function registerCommands() { - Artisan::command('sail:install', function () { - copy(__DIR__.'/../stubs/docker-compose.yml', base_path('docker-compose.yml')); - - $environment = file_get_contents(base_path('.env')); - - $environment = str_replace('DB_HOST=127.0.0.1', 'DB_HOST=mysql', $environment); - $environment = str_replace('MEMCACHED_HOST=127.0.0.1', 'MEMCACHED_HOST=memcached', $environment); - $environment = str_replace('REDIS_HOST=127.0.0.1', 'REDIS_HOST=redis', $environment); - - file_put_contents(base_path('.env'), $environment); - - $this->info('Sail scaffolding installed successfully.'); - })->purpose('Install Laravel Sail\'s default Docker Compose file'); - - Artisan::command('sail:publish', function () { - $this->call('vendor:publish', ['--tag' => 'sail']); - - file_put_contents(base_path('docker-compose.yml'), str_replace( - './vendor/laravel/sail/runtimes/8.0', - './docker/8.0', - file_get_contents(base_path('docker-compose.yml')) - )); - })->purpose('Publish the Laravel Sail Docker files'); + if ($this->app->runningInConsole()) { + $this->commands([ + InstallCommand::class, + PublishCommand::class, + ]); + } } /** @@ -60,9 +42,11 @@ protected function registerCommands() */ protected function configurePublishing() { - $this->publishes([ - __DIR__.'/../runtimes' => base_path('docker'), - ], 'sail'); + if ($this->app->runningInConsole()) { + $this->publishes([ + __DIR__ . '/../runtimes' => $this->app->basePath('docker'), + ], 'sail'); + } } /** @@ -73,8 +57,8 @@ protected function configurePublishing() public function provides() { return [ - 'sail.install-command', - 'sail.publish-command', + InstallCommand::class, + PublishCommand::class, ]; } } diff --git a/stubs/docker-compose.stub b/stubs/docker-compose.stub new file mode 100644 index 00000000..90578508 --- /dev/null +++ b/stubs/docker-compose.stub @@ -0,0 +1,25 @@ +# For more information: https://laravel.com/docs/sail +version: '3' +services: + laravel.test: + build: + context: ./vendor/laravel/sail/runtimes/8.0 + dockerfile: Dockerfile + args: + WWWGROUP: '${WWWGROUP}' + image: sail-8.0/app + ports: + - '${APP_PORT:-80}:80' + environment: + WWWUSER: '${WWWUSER}' + LARAVEL_SAIL: 1 + volumes: + - '.:/var/www/html' + networks: + - sail + {{depends}} +{{services}} +networks: + sail: + driver: bridge +{{volumes}} diff --git a/stubs/docker-compose.yml b/stubs/docker-compose.yml deleted file mode 100644 index 479451b8..00000000 --- a/stubs/docker-compose.yml +++ /dev/null @@ -1,88 +0,0 @@ -# For more information: https://laravel.com/docs/sail -version: '3' -services: - laravel.test: - build: - context: ./vendor/laravel/sail/runtimes/8.0 - dockerfile: Dockerfile - args: - WWWGROUP: '${WWWGROUP}' - image: sail-8.0/app - ports: - - '${APP_PORT:-80}:80' - environment: - WWWUSER: '${WWWUSER}' - LARAVEL_SAIL: 1 - volumes: - - '.:/var/www/html' - networks: - - sail - depends_on: - - mysql -# - pgsql - - redis -# - selenium -# selenium: -# image: 'selenium/standalone-chrome' -# volumes: -# - '/dev/shm:/dev/shm' -# networks: -# - sail - mysql: - image: 'mysql:8.0' - ports: - - '${FORWARD_DB_PORT:-3306}:3306' - environment: - MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}' - MYSQL_DATABASE: '${DB_DATABASE}' - MYSQL_USER: '${DB_USERNAME}' - MYSQL_PASSWORD: '${DB_PASSWORD}' - MYSQL_ALLOW_EMPTY_PASSWORD: 'yes' - volumes: - - 'sailmysql:/var/lib/mysql' - networks: - - sail - healthcheck: - test: ["CMD", "mysqladmin", "ping"] -# pgsql: -# image: postgres:13 -# ports: -# - '${FORWARD_DB_PORT:-5432}:5432' -# environment: -# PGPASSWORD: '${DB_PASSWORD:-secret}' -# POSTGRES_DB: '${DB_DATABASE}' -# POSTGRES_USER: '${DB_USERNAME}' -# POSTGRES_PASSWORD: '${DB_PASSWORD:-secret}' -# volumes: -# - 'sailpostgresql:/var/lib/postgresql/data' -# networks: -# - sail -# healthcheck: -# test: ["CMD", "pg_isready", "-q", "-d", "${DB_DATABASE}", "-U", "${DB_USERNAME}"] - redis: - image: 'redis:alpine' - ports: - - '${FORWARD_REDIS_PORT:-6379}:6379' - volumes: - - 'sailredis:/data' - networks: - - sail - healthcheck: - test: ["CMD", "redis-cli", "ping"] - mailhog: - image: 'mailhog/mailhog:latest' - ports: - - '${FORWARD_MAILHOG_PORT:-1025}:1025' - - '${FORWARD_MAILHOG_DASHBOARD_PORT:-8025}:8025' - networks: - - sail -networks: - sail: - driver: bridge -volumes: - sailmysql: - driver: local -# sailpostgresql: -# driver: local - sailredis: - driver: local diff --git a/stubs/mailhog.stub b/stubs/mailhog.stub new file mode 100644 index 00000000..ebbf5591 --- /dev/null +++ b/stubs/mailhog.stub @@ -0,0 +1,7 @@ + mailhog: + image: 'mailhog/mailhog:latest' + ports: + - '${FORWARD_MAILHOG_PORT:-1025}:1025' + - '${FORWARD_MAILHOG_DASHBOARD_PORT:-8025}:8025' + networks: + - sail diff --git a/stubs/meilisearch.stub b/stubs/meilisearch.stub new file mode 100644 index 00000000..bf4705ff --- /dev/null +++ b/stubs/meilisearch.stub @@ -0,0 +1,8 @@ + meilisearch: + image: 'getmeili/meilisearch:latest' + ports: + - '${FORWARD_MEILISEARCH_PORT:-7700}:7700' + volumes: + - 'sailmeilisearch:/data.ms' + networks: + - sail diff --git a/stubs/mysql.stub b/stubs/mysql.stub new file mode 100644 index 00000000..8ca5bbc9 --- /dev/null +++ b/stubs/mysql.stub @@ -0,0 +1,16 @@ + mysql: + image: 'mysql:8.0' + ports: + - '${FORWARD_DB_PORT:-3306}:3306' + environment: + MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}' + MYSQL_DATABASE: '${DB_DATABASE}' + MYSQL_USER: '${DB_USERNAME}' + MYSQL_PASSWORD: '${DB_PASSWORD}' + MYSQL_ALLOW_EMPTY_PASSWORD: 'yes' + volumes: + - 'sailmysql:/var/lib/mysql' + networks: + - sail + healthcheck: + test: ["CMD", "mysqladmin", "ping"] diff --git a/stubs/pgsql.stub b/stubs/pgsql.stub new file mode 100644 index 00000000..fdabc4d0 --- /dev/null +++ b/stubs/pgsql.stub @@ -0,0 +1,15 @@ + pgsql: + image: postgres:13 + ports: + - '${FORWARD_DB_PORT:-5432}:5432' + environment: + PGPASSWORD: '${DB_PASSWORD:-secret}' + POSTGRES_DB: '${DB_DATABASE}' + POSTGRES_USER: '${DB_USERNAME}' + POSTGRES_PASSWORD: '${DB_PASSWORD:-secret}' + volumes: + - 'sailpostgresql:/var/lib/postgresql/data' + networks: + - sail + healthcheck: + test: ["CMD", "pg_isready", "-q", "-d", "${DB_DATABASE}", "-U", "${DB_USERNAME}"] diff --git a/stubs/redis.stub b/stubs/redis.stub new file mode 100644 index 00000000..4f947b83 --- /dev/null +++ b/stubs/redis.stub @@ -0,0 +1,10 @@ + redis: + image: 'redis:alpine' + ports: + - '${FORWARD_REDIS_PORT:-6379}:6379' + volumes: + - 'sailredis:/data' + networks: + - sail + healthcheck: + test: ["CMD", "redis-cli", "ping"] diff --git a/stubs/selenium.stub b/stubs/selenium.stub new file mode 100644 index 00000000..ac220375 --- /dev/null +++ b/stubs/selenium.stub @@ -0,0 +1,6 @@ + selenium: + image: 'selenium/standalone-chrome' + volumes: + - '/dev/shm:/dev/shm' + networks: + - sail