diff --git a/changelog.md b/changelog.md
index 99a9e68..61b4600 100644
--- a/changelog.md
+++ b/changelog.md
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [1.3.0] - 2023-03-30
+
+* Change - Leverage Docker Compose syntax to manage network aliases and service dependencies. Clean up a remove code.
+* Add the `dc` command to run Docker Compose commands in the stack.
+* Support the `SLIC_DOCKER_COMPOSE_BIN` environment variable to allow for the use a different Docker Compose binary, the `docker compose` one is used by default.
+
## [1.2.4] - 2023-03-21
* Fix - [issue 142](https://github.com/stellarwp/slic/issues/142) ensure the hosts file in the docker container contains a tab character before trying to explode it.
diff --git a/slic-stack.site.yml b/slic-stack.site.yml
index 7f59602..ff7bae6 100644
--- a/slic-stack.site.yml
+++ b/slic-stack.site.yml
@@ -1,4 +1,4 @@
-# docker-compose configuration file used to run cross-activation tests.
+# docker compose configuration file used to run cross-activation tests.
version: "3"
@@ -8,13 +8,13 @@ services:
volumes:
# Paths are relative to the directory that contains this file, NOT the current working directory.
# Share the WordPress core installation files in the `_wordpress` directory.
- - ${SLIC_WP_DIR}:/var/www/html:cached
+ - ${SLIC_WP_DIR}:/var/www/html
cli:
volumes:
# Paths are relative to the directory that contains this file, NOT the current working directory.
# Share the WordPress core installation files in the `_wordpress` directory.
- - ${SLIC_WP_DIR}:/var/www/html:cached
+ - ${SLIC_WP_DIR}:/var/www/html
codeception:
environment:
@@ -22,18 +22,18 @@ services:
CODECEPTION_PROJECT_DIR: /var/www/html/${SLIC_CURRENT_PROJECT_RELATIVE_PATH}
volumes:
# Set the current site as project.
- - ${SLIC_HERE_DIR}/${SLIC_CURRENT_PROJECT_RELATIVE_PATH}:/project:cached
+ - ${SLIC_HERE_DIR}/${SLIC_CURRENT_PROJECT_RELATIVE_PATH}:/project
# Paths are relative to the directory that contains this file, NOT the current working directory.
# Share the WordPress core installation files in the `_wordpress` directory.
- - ${SLIC_WP_DIR}:/var/www/html:cached
+ - ${SLIC_WP_DIR}:/var/www/html
composer:
volumes:
# Set the current target as project.
- - ${SLIC_HERE_DIR}/${SLIC_CURRENT_PROJECT_RELATIVE_PATH}:/project:cached
- - ${COMPOSER_CACHE_DIR}:${COMPOSER_CACHE_DIR}:cached
+ - ${SLIC_HERE_DIR}/${SLIC_CURRENT_PROJECT_RELATIVE_PATH}:/project
+ - ${COMPOSER_CACHE_DIR}:${COMPOSER_CACHE_DIR}
npm:
volumes:
# Set the current plugin as project.
- - ${SLIC_HERE_DIR}/${SLIC_CURRENT_PROJECT_RELATIVE_PATH}:/project:cached
+ - ${SLIC_HERE_DIR}/${SLIC_CURRENT_PROJECT_RELATIVE_PATH}:/project
diff --git a/slic-stack.yml b/slic-stack.yml
index 92eb16b..2a406c1 100644
--- a/slic-stack.yml
+++ b/slic-stack.yml
@@ -1,6 +1,6 @@
-# docker-compose configuration file used to run cross-activation tests.
+# docker compose configuration file used to run cross-activation tests.
-version: "3"
+version: "3.9"
networks:
slic:
@@ -11,7 +11,7 @@ volumes:
services:
db:
- image: mariadb:10.7.3
+ image: mariadb:10.7.8
networks:
- slic
ports:
@@ -19,25 +19,45 @@ services:
environment:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-root}
+ healthcheck: # The `test` db should exist.
+ test: mysqlshow -u root -p${MYSQL_ROOT_PASSWORD:-root} test
+ start_period: 5s
+ interval: 1s
+ timeout: 3s
+ retries: 30
tmpfs:
- /var/lib/mysql
redis:
- image: redis
+ image: redis:7.0.10
networks:
- slic:
+ - slic
ports:
- "${SLIC_REDIS_LOCALHOST_PORT:-8379}:6379"
+ healthcheck: # It should reply PONG to PING
+ test: redis-cli ping | grep PONG
+ start_period: 2s
+ interval: 1s
+ timeout: 3s
+ retries: 30
tmpfs:
- /data
wordpress:
image: ghcr.io/stellarwp/slic-wordpress-php${SLIC_PHP_VERSION}:${SLIC_VERSION}
networks:
- - slic
+ slic:
+ aliases: # Allow reaching the site at `http://wordpress.test` and other domains that might be used in testing.
+ - wordpress.test
+ - www.wordpress.test
+ - test1.wordpress.test
+ - test2.wordpress.test
+ - test3.wordpress.test
depends_on:
- - db
- - redis
+ db:
+ condition: service_healthy
+ redis:
+ condition: service_healthy
# Run the container as the host user and group.
# Apache will run as the same user and permission issues with WordPress generated files should not arise.
user: "${SLIC_UID:-}:${SLIC_GID:-}"
@@ -69,6 +89,8 @@ services:
define( 'TRIBE_NO_FREEMIUS', true );
define( 'WP_DEBUG_DISPLAY', true );
define( 'WP_DEBUG_LOG', true );
+ define( 'DISABLE_WP_CRON', true );
+ define( 'WP_HTTP_BLOCK_EXTERNAL', true );
# Configure this to debug the tests with XDebug.
# Map the `_wordpress` directory to `/var/www/html' directory in your IDE of choice.
# Map the `_plugins` directory to `/plugins` directory in your IDE of choice.
@@ -76,29 +98,49 @@ services:
# The `remote_host` is set to `host.docker.internal` that will resolve to the host machine IP address, from
# within the container, on macOS and Windows.
# On Linux set the host machine IP address before calling the stack:
- # XDH=$(ip route | grep docker0 | awk '{print $9}') docker-compose ...
+ # XDH=$(ip route | grep docker0 | awk '{print $9}') docker compose ...
XDEBUG_CONFIG: "idekey=${XDK:-slic} remote_enable=${XDE:-1} remote_host=${XDH:-host.docker.internal} remote_port=${XDP:-9001} client_host=${XDH:-host.docker.internal} client_port=${XDP:-9001}"
# Whether to disable the XDebug extension in the Codeception container completely or not.
XDEBUG_DISABLE: "${XDEBUG_DISABLE:-0}"
volumes:
# Paths are relative to the directory that contains this file, NOT the current working directory.
- - ${SLIC_WP_DIR}:/var/www/html:cached
- - ${SLIC_PLUGINS_DIR}:/var/www/html/wp-content/plugins:cached
- - ${SLIC_THEMES_DIR}:/var/www/html/wp-content/themes:cached
- - ${COMPOSER_CACHE_DIR:-./.cache}:/composer-cache:cached
+ - ${SLIC_WP_DIR}:/var/www/html
+ - ${SLIC_PLUGINS_DIR}:/var/www/html/wp-content/plugins
+ - ${SLIC_THEMES_DIR}:/var/www/html/wp-content/themes
+ - ${COMPOSER_CACHE_DIR:-./.cache}:/composer-cache
+ healthcheck: # Apache service should be running correctly.
+ test: service apache2 status
+ start_period: 5s
+ interval: 1s
+ timeout: 3s
+ retries: 30
chrome:
- image: ${SLIC_CHROME_CONTAINER:-selenium/standalone-chrome:3.141.59-oxygen}
+ image: ${SLIC_CHROME_CONTAINER:-selenium/standalone-chrome:3.141.59}
networks:
- slic
- extra_hosts:
- - "wordpress.test:172.${SLIC_TEST_SUBNET:-28}.1.1"
+ depends_on:
+ wordpress:
+ condition: service_healthy
+ healthcheck: # It should reply with a 200 status code to a request to the status endpoint.
+ test: curl -f http://localhost:4444/wd/hub/status
+ start_period: 5s
+ interval: 1s
+ timeout: 3s
+ retries: 30
slic:
image: ghcr.io/stellarwp/slic-php${SLIC_PHP_VERSION}:${SLIC_VERSION}
networks:
- slic
user: "${SLIC_UID:-}:${SLIC_GID:-}"
+ depends_on:
+ db:
+ condition: service_healthy
+ chrome:
+ condition: service_healthy
+ wordpress:
+ condition: service_healthy
environment:
COMPOSER_AUTH: "${COMPOSER_AUTH:-}"
COMPOSER_CACHE_DIR: "/composer-cache"
@@ -115,7 +157,7 @@ services:
# The `remote_host` is set to `host.docker.internal` that will resolve to the host machine IP address, from
# within the container, on macOS and Windows.
# On Linux set the host machine IP address before calling the stack:
- # XDH=$(ip route | grep docker0 | awk '{print $9}') docker-compose ...
+ # XDH=$(ip route | grep docker0 | awk '{print $9}') docker compose ...
XDEBUG_CONFIG: "idekey=${XDK:-slic} remote_enable=${XDE:-1} remote_host=${XDH:-host.docker.internal} remote_port=${XDP:-9001} client_host=${XDH:-host.docker.internal} client_port=${XDP:-9001}"
# Move to the target directory before running the command from the plugins directory.
CODECEPTION_PROJECT_DIR: /var/www/html/wp-content/plugins/${SLIC_CURRENT_PROJECT:-test}/${SLIC_CURRENT_PROJECT_SUBDIR:-}
@@ -137,10 +179,10 @@ services:
volumes:
# Paths are relative to the directory that contains this file, NOT the current working directory.
# Share the WordPress core installation files in the `_wordpress` directory.
- - ${SLIC_WP_DIR}:/var/www/html:cached
+ - ${SLIC_WP_DIR}:/var/www/html
# Share the plugins in the `/var/www/hmtl/wp-content/plugins` directory.
- - ${SLIC_PLUGINS_DIR}:/var/www/html/wp-content/plugins:cached
- - ${SLIC_THEMES_DIR}:/var/www/html/wp-content/themes:cached
+ - ${SLIC_PLUGINS_DIR}:/var/www/html/wp-content/plugins
+ - ${SLIC_THEMES_DIR}:/var/www/html/wp-content/themes
# In some plugins we use function-mocker and set it up to cache in `/tmp/function-mocker`.
# To avoid a long re-caching on each run, let's cache in a docker volume, caching on the host
# filesystem would be a worse cure than the disease.
@@ -148,32 +190,4 @@ services:
- function-mocker-cache:/cache
- ${COMPOSER_CACHE_DIR:-./.cache}:/composer-cache
# Scripts volume
- - ${SLIC_SCRIPTS}:/slic-scripts:cached
-
-# adminer:
-# image: adminer
-# networks:
-# - slic
-# environment:
-# ADMINER_DEFAULT_SERVER: db
-# ports:
-# - "9080:8080"
-#
-#
-# redis-cli:
-# image: redis
-# networks:
-# slic:
-# depends_on:
-# - redis
-# entrypoint: ["redis-cli","-h redis","-p 6379"]
-# command: ["--version"]
-#
-# mailcatcher:
-# image: dockage/mailcatcher
-# networks:
-# slic:
-# ports:
-# # Expose MailCatcher ports on localhost.
-# - "1025:1025"
-# - "1080:1080"
+ - ${SLIC_SCRIPTS}:/slic-scripts
diff --git a/slic.md b/slic.md
index 8050580..4456e89 100644
--- a/slic.md
+++ b/slic.md
@@ -7,7 +7,7 @@ The entrypoint to anything you will need to do will be the `slic` binary, locate
## Requirements
-The stack runs based on [Docker](https://www.docker.com/) and [docker-compose](https://docs.docker.com/compose/): you will need both installed and available to be able to use the local testing environment.
+The stack runs based on [Docker](https://www.docker.com/) and [docker compose](https://docs.docker.com/compose/): you will need both installed and available to be able to use the local testing environment.
If your Docker installation requires root access, please follow [this guide](https://docs.docker.com/install/linux/linux-postinstall/) to make sure root access is not required to run `docker` commands.
You should be able to run the following command without issues and without requiring root access:
@@ -16,7 +16,7 @@ You should be able to run the following command without issues and without requi
docker run hello-world
```
-If this is not the case, please take the time to read Docker and docker-compose documentation and fix the issues you encounter.
+If this is not the case, please take the time to read Docker and docker compose documentation and fix the issues you encounter.
## Where to get help
@@ -178,7 +178,7 @@ slic cli db export /plugins/the-events/calendar/tests/_data/dump.sql
## How the stack works, an overview
The stack services are defined by the `slic-stack.yml` file.
-This is a YAML format docker-compose configuration file the `slic` binary will use to run the `docker-compose` command.
+This is a YAML format docker compose configuration file the `slic` binary will use to run the `docker compose` command.
The main services defined there are:
* `wordpress` - this uses the `wordpress:latest` image, the official Docker image for WordPress. When running the container will fill the `_wordpress` directory with the contents of the WordPress installation that is currently serving the container. Furthermore the WordPress container is configured to look for plugins in the `/plugins` directory, that directory is a shared volume that you can find in the `dev/test/plugins` directory.
diff --git a/slic.php b/slic.php
index acec560..295ff43 100644
--- a/slic.php
+++ b/slic.php
@@ -1,5 +1,7 @@
slic at https://github.com/stellarwp/slic
@@ -92,6 +96,7 @@
config Prints the stack configuration as interpolated from the environment.
debug Activates or deactivates {$cli_name} debug output or returns the current debug status.
down Tears down the stack; alias of `stop`.
+ dc Runs a docker compose command in the stack.
exec Runs a bash command in the stack.
group Create or remove group of targets for the current plugins directory.
host-ip Returns the IP Address of the host machine from the container perspective.
@@ -114,12 +119,13 @@
$is_help = args( [ 'help' ], $args( '...' ), 0 )( 'help', false ) === 'help';
-$run_settings_file = root( '/.env.slic.run' );
$original_subcommand = $args( 'subcommand' );
$subcommand = $args( 'subcommand', 'help' );
-$cli_name = basename( $argv[0] );
+// Both these variables will be used by commands.
+$run_settings_file = root( '/.env.slic.run' );
+$cli_name = basename( $argv[0] );
if ( 'help' !== $subcommand ) {
maybe_prompt_for_repo_update();
@@ -132,82 +138,45 @@
}
}
-if ( ! in_array( $subcommand, [ 'help', 'update'] ) ) {
+if ( ! in_array( $subcommand, [ 'help', 'update' ] ) ) {
+ maybe_prompt_for_stack_update();
+}
+
+if ( empty( $subcommand ) || $subcommand === 'help' ) {
+ echo $help_message . PHP_EOL;
+ if ( $original_subcommand ) {
+ echo PHP_EOL . $help_advanced_message;
+ } else {
+ echo colorize( PHP_EOL . "There are a lot more commands. Use slic help to see them all!" . PHP_EOL );
+ }
+ maybe_prompt_for_repo_update();
maybe_prompt_for_stack_update();
+ echo PHP_EOL;
+ exit( 0 );
}
-// A map from the user-facing alias to the command that will be actually called.
+/*
+ * Resolve command aliases.
+ * A map from the user-facing alias to the command that will be actually called.
+ */
$aliases = [
'wp' => 'cli',
];
+if ( isset( $aliases[ $subcommand ] ) ) {
+ $subcommand = $aliases[ $subcommand ];
+}
-switch ( $subcommand ) {
- default:
- case 'help':
- echo $help_message . PHP_EOL;
- if ( $original_subcommand ) {
- echo PHP_EOL . $help_advanced_message;
- } else {
- echo colorize( PHP_EOL . "There are a lot more commands. Use slic help to see them all!" . PHP_EOL );
- }
- maybe_prompt_for_repo_update();
- maybe_prompt_for_stack_update();
- break;
- case 'cc':
- case 'restart':
- case 'run':
- case 'serve':
- case 'shell':
- case 'site-cli':
- case 'ssh':
- case 'up':
- // ensure_wordpress_files();
- // ensure_wordpress_configured();
- // Do not break, let the command be loaded then.
- case 'airplane-mode':
- case 'cache':
- case 'cli':
- case 'wp': // Alias of the `cli` command.
- // ensure_wordpress_installed();
- // Do not break, let the command be loaded then.
- case 'build-prompt':
- case 'build-stack':
- case 'build-subdir':
- case 'composer':
- case 'composer-cache':
- case 'config':
- case 'debug':
- case 'down':
- case 'exec':
- case 'here':
- case 'host-ip':
- case 'info':
- case 'init':
- case 'interactive':
- case 'logs':
- case 'mysql':
- case 'npm':
- case 'npm_lts':
- case 'phpcbf':
- case 'phpcs':
- case 'ps':
- case 'php-version':
- case 'reset':
- case 'start':
- case 'stop':
- case 'target':
- case 'update':
- case 'upgrade':
- case 'use':
- case 'using':
- case 'xdebug':
- if ( isset( $aliases[ $subcommand ] ) ) {
- $subcommand = $aliases[ $subcommand ];
- }
- include_once __DIR__ . '/src/commands/' . $subcommand . '.php';
- break;
+$subcommand_file = __DIR__ . '/src/commands/' . $subcommand . '.php';
+if ( file_exists( $subcommand_file ) ) {
+ include_once $subcommand_file;
+} else {
+ echo colorize( "Unknown command: {$subcommand}" . PHP_EOL . PHP_EOL );
+ echo $help_message . PHP_EOL;
+ maybe_prompt_for_repo_update();
+ maybe_prompt_for_stack_update();
+ echo PHP_EOL;
+ exit( 1 );
}
// Add a break line at the end of each command to avoid dirty terminal issues.
echo PHP_EOL;
-
diff --git a/src/cache.php b/src/cache.php
new file mode 100644
index 0000000..7773403
--- /dev/null
+++ b/src/cache.php
@@ -0,0 +1,50 @@
+get( $key, $found );
+
+ if ( $found ) {
+ return $value;
+ }
+
+ return $default;
+}
+
+/**
+ * Sets a value in the cache.
+ *
+ * @param string $key
+ * @param $value
+ *
+ * @return void
+ */
+function slic_cache_set( string $key, $value ) {
+ global $slic_cache;
+
+ $slic_cache->set( $key, $value );
+}
+
+/**
+ * Flushes the cache.
+ *
+ * @return void
+ */
+function slic_cache_flush(): void {
+ global $slic_cache;
+ $slic_cache->flush();
+}
diff --git a/src/classes/Cache.php b/src/classes/Cache.php
new file mode 100644
index 0000000..3329b0f
--- /dev/null
+++ b/src/classes/Cache.php
@@ -0,0 +1,63 @@
+
+ */
+ private array $cache = [];
+
+ /**
+ * Gets a value from the cache.
+ *
+ * @param string $key
+ * @param bool $found
+ *
+ * @return mixed|null
+ */
+ public function get( string $key, ?bool &$found ) {
+ if ( isset( $this->cache[ $key ] ) ) {
+ $found = true;
+
+ return $this->cache[ $key ];
+ }
+
+ $found = false;
+
+ return null;
+ }
+
+ /**
+ * Sets a value in the cache.
+ *
+ * @param string $key
+ * @param $value
+ *
+ * @return void
+ */
+ public function set( string $key, $value ): void {
+ $this->cache[ $key ] = $value;
+ }
+
+ /**
+ * Flushes the cache.
+ *
+ * @return void
+ */
+ public function flush() {
+ $this->cache = [];
+ }
+}
diff --git a/src/classes/Callback_Stack.php b/src/classes/Callback_Stack.php
deleted file mode 100644
index 9deac2e..0000000
--- a/src/classes/Callback_Stack.php
+++ /dev/null
@@ -1,45 +0,0 @@
-
- */
- private $callbacks = [];
-
- public function call(): void {
- foreach ( $this->callbacks as $callback_id => $callback ) {
- $callback();
-
- // Remove the callback from the stack after it has been called.
- $this->remove( $callback_id );
- }
- }
-
- /**
- * Add a callback to the stack, with a specified priority.
- *
- * @param string $callback_id The callback ID.
- * @param callable $callback The callback to add.
- *
- * @return void The callback is added to the stack.
- */
- public function add( string $callback_id, callable $callback ): void {
- $this->callbacks[ $callback_id ] = $callback;
- }
-
- /**
- * Remove a callback from the stack.
- *
- * @param string $callback_id The callback ID.
- *
- * @return void The callback is removed from the stack.
- */
- private function remove( $callback_id ) {
- unset( $this->callbacks[ $callback_id ] );
- }
-}
diff --git a/src/codeception.php b/src/codeception.php
deleted file mode 100644
index e43a16d..0000000
--- a/src/codeception.php
+++ /dev/null
@@ -1,39 +0,0 @@
- A list of service dependencies required to run
- * a Codeception command.
- */
-function codeception_dependencies( array $codeception_args = [] ) {
- if ( empty( $codeception_args ) ) {
- return [];
- }
-
- $dependencies = [];
-
- if ( count( array_intersect( [
- 'run',
- ], $codeception_args ) ) ) {
- $dependencies[] = 'wordpress';
- $dependencies[] = 'db';
- }
-
- return array_values( array_unique( array_filter( $dependencies ) ) );
-}
diff --git a/src/commands.php b/src/commands.php
index cb96542..d4160d5 100644
--- a/src/commands.php
+++ b/src/commands.php
@@ -20,5 +20,7 @@ function command_stop() : int {
echo colorize( PHP_EOL . "โ Some containers failed to stop. Use slic ps to see what is still running." . PHP_EOL );
}
+ slic_cache_flush();
+
return $status;
-}
\ No newline at end of file
+}
diff --git a/src/commands/airplane-mode.php b/src/commands/airplane-mode.php
index 33e8a2b..8960e2b 100644
--- a/src/commands/airplane-mode.php
+++ b/src/commands/airplane-mode.php
@@ -40,7 +40,6 @@
$activate = $toggle === 'on';
setup_id();
-ensure_service_running( 'slic' );
ensure_wordpress_ready();
$ensure_airplane_mode_plugin = static function () {
diff --git a/src/commands/cache.php b/src/commands/cache.php
index 8432ecd..ad46d20 100644
--- a/src/commands/cache.php
+++ b/src/commands/cache.php
@@ -42,7 +42,6 @@
$toggle = $cache_args( 'toggle', 'status' );
setup_id();
-ensure_services_running( [ 'wordpress', 'slic' ] );
ensure_wordpress_ready();
// Ensure the plugin is installed.
diff --git a/src/commands/cc.php b/src/commands/cc.php
index 58eb88b..193139c 100644
--- a/src/commands/cc.php
+++ b/src/commands/cc.php
@@ -38,7 +38,7 @@
setup_id();
$codeception_args = $args( '...' );
-ensure_service_running( 'slic', codeception_dependencies( $codeception_args ) );
+ensure_service_running( 'slic' );
$codeception_config = '';
if ( file_exists( get_project_local_path() . '/codeception.slic.yml' ) ) {
diff --git a/src/commands/cli.php b/src/commands/cli.php
index 305c7ac..e65b71a 100644
--- a/src/commands/cli.php
+++ b/src/commands/cli.php
@@ -34,7 +34,6 @@
}
setup_id();
-ensure_services_running( [ 'slic', 'db' ] );
ensure_wordpress_ready();
// Runs a wp-cli command in the stack, using the `cli` service.
diff --git a/src/commands/dc.php b/src/commands/dc.php
new file mode 100644
index 0000000..4b11bcb
--- /dev/null
+++ b/src/commands/dc.php
@@ -0,0 +1,39 @@
+{$cli_name} dc [...]
+
+ EXAMPLES:
+
+ {$cli_name} dc ps
+ List the containers in the stack.
+
+ {$cli_name} dc up redis
+ Starts the Redis container.
+
+ HELP;
+
+ echo colorize( $help );
+
+ return;
+}
+
+$dc_args = $args( '...' );
+exit( slic_realtime()( $dc_args ) );
diff --git a/src/commands/run.php b/src/commands/run.php
index a39e642..76ae191 100644
--- a/src/commands/run.php
+++ b/src/commands/run.php
@@ -47,7 +47,7 @@
echo light_cyan( "Using {$using}" . PHP_EOL );
$codeception_args = array_merge( [ 'run' ], $args( '...' ) );
-ensure_service_running( 'slic', codeception_dependencies( $codeception_args ) );
+ensure_service_running( 'slic' );
setup_id();
diff --git a/src/commands/site-cli.php b/src/commands/site-cli.php
index 5295afd..14f78aa 100644
--- a/src/commands/site-cli.php
+++ b/src/commands/site-cli.php
@@ -30,8 +30,6 @@
}
setup_id();
-
-ensure_services_running( [ 'wordpress', 'slic' ] );
ensure_wordpress_ready();
$command = $args( '...' );
@@ -75,7 +73,7 @@
array_unshift( $command, 'wp', '--allow-root' );
/*
- * Due to how docker-compose works, the default `CMD` for the `wordpress:cli` image will be overridden as a
+ * Due to how docker compose works, the default `CMD` for the `wordpress:cli` image will be overridden as a
* consequence of overriding the `entrypoint` configuration parameter of the service.
* We cannot, thus, pass the user command directly, we use an env var, `SLIC_SITE_CLI_COMMAND`, to embed the
* command we're running into the entrypoint call arguments.
diff --git a/src/database.php b/src/database.php
index 508b932..b722671 100644
--- a/src/database.php
+++ b/src/database.php
@@ -21,7 +21,7 @@ function ensure_db_service_running() {
}
// Start the service is not already started.
- $status = slic_passive()( [ 'up', '--detach', 'db' ] );
+ $status = slic_passive()( [ 'up', '--wait', 'db' ] );
if ( $status !== 0 ) {
echo magenta( 'Failed to start or restart the database service; check the output for errors.' );
@@ -135,33 +135,3 @@ function get_db_user() {
function get_db_password() {
return 'password';
}
-
-/**
- * Starts the stack database service, if required.
- *
- * @return bool Always `true` to indicate the database service was correctly started.
- */
-function ensure_db_service_ready() {
- setup_slic_env( root() );
- ensure_db_service_running();
-
- $attempts = 0;
- while ( $attempts ++ < 30 ) {
- debug( "Waiting for database to be ready ..." . PHP_EOL );
-
- try {
- $mysqli = get_localhost_db_handle();
- if ( $mysqli instanceof mysqli ) {
- debug( "Database ready." . PHP_EOL );
-
- return true;
- }
- } catch ( Exception $e ) {
- // No-op, just wait.
- }
- sleep( 1 );
- }
-
- echo magenta( "Database never became available." . PHP_EOL );
- exit( 1 );
-}
diff --git a/src/docker.php b/src/docker.php
index 3dc25b6..579c590 100644
--- a/src/docker.php
+++ b/src/docker.php
@@ -1,6 +1,6 @@
$options A list of options to initialize the wrapper.
*
- * @return \Closure A closure to actually call docker-compose with more arguments.
+ * @return \Closure A closure to actually call docker compose with more arguments.
*/
function docker_compose( array $options = [] ) {
setup_id();
@@ -49,8 +49,10 @@ function docker_compose( array $options = [] ) {
$host_ip = host_ip( 'Linux' );
}
- return static function ( array $command = [] ) use ( $options, $host_ip, $is_ci ) {
- $command = 'docker-compose ' . implode( ' ', $options ) . ' ' . implode( ' ', $command );
+ $dc_bin = docker_compose_bin();
+
+ return static function ( array $command = [] ) use ( $dc_bin, $options, $host_ip, $is_ci ) {
+ $command = $dc_bin . ' ' . implode( ' ', $options ) . ' ' . implode( ' ', $command );
if ( ! empty( $host_ip ) ) {
// Set the host IP address on Linux machines.
@@ -122,7 +124,7 @@ function wordpress_url() {
* @param string $postfix A postfix to use for the stack file, it will be inserted between the file base name and
* the `.yml` file extension.
*
- * @return string The path to the docker-compose stack file to run, depending on the run context.
+ * @return string The path to the docker compose stack file to run, depending on the run context.
*/
function stack( $postfix = '' ) {
$root_dir = dirname( __DIR__ );
@@ -143,13 +145,13 @@ function stack( $postfix = '' ) {
}
/**
- * Builds a collection of docker-compose yaml files for spinning up a stack.
+ * Builds a collection of docker compose yaml files for spinning up a stack.
*
* Typically, this would be slic-stack.yml for plugin-only setups, but if running in site mode, it adds slic-stack.site.yml.
*
* @param bool $filenames_only Return only the files part of the stack, without including option flags.
*
- * @return string[] Array of docker-compose arguments indicating the files that should be used to initialize the stack.
+ * @return string[] Array of docker compose arguments indicating the files that should be used to initialize the stack.
*/
function slic_stack_array( $filenames_only = false ) {
$file_prefix = $filenames_only ? '' : '-f';
@@ -166,7 +168,7 @@ function slic_stack_array( $filenames_only = false ) {
}
/**
- * Executes a docker-compose command in real time, printing the output as produced by the command.
+ * Executes a docker compose command in real time, printing the output as produced by the command.
*
* @param array $options A list of options to initialize the wrapper.
* @param bool $is_realtime Whether the command should be run in real time (true) or passively (false).
@@ -204,7 +206,7 @@ function docker_compose_process( array $options = [], $is_realtime = true ) {
$command = array_unique( array_merge( [ $subcommand ], $var, $command ) );
}
- $command = 'docker-compose ' . implode( ' ', $options ) . ' ' . implode( ' ', $command );
+ $command = docker_compose_bin() . ' ' . implode( ' ', $options ) . ' ' . implode( ' ', $command );
if ( ! empty( $host_ip ) ) {
// Set the host IP address on Linux machines.
@@ -222,7 +224,7 @@ function docker_compose_process( array $options = [], $is_realtime = true ) {
}
/**
- * Executes a docker-compose command in passive mode, printing the output as produced by the command.
+ * Executes a docker compose command in passive mode, printing the output as produced by the command.
*
* This approach is used for commands that can be run in a parallel or forked process without interactivity.
*
@@ -235,7 +237,7 @@ function docker_compose_passive( array $options = [] ) {
}
/**
- * Executes a docker-compose command in real time, printing the output as produced by the command.
+ * Executes a docker compose command in real time, printing the output as produced by the command.
*
* @param array $options A list of options to initialize the wrapper.
*
@@ -244,3 +246,18 @@ function docker_compose_passive( array $options = [] ) {
function docker_compose_realtime( array $options = [] ) {
return docker_compose_process( $options, true );
}
+
+/**
+ * Returns the path to the docker compose binary.
+ *
+ * Newer versions of Docker include the `docker compose` command instead of a separate `docker-compose`.
+ * Most CIs have the newer version of Docker that includes the `docker compose` command, but will also include the
+ * outdated `docker-compose` command for back-compatibility.
+ * Unless the `SLIC_DOCKER_COMPOSE_BIN` environment variable is set, we'll use the newer `docker compose` command.
+ *
+ * @return string
+ */
+function docker_compose_bin(): string {
+ return (string) getenv( 'SLIC_DOCKER_COMPOSE_BIN' ) ?: 'docker compose';
+}
+
diff --git a/src/services.php b/src/services.php
index 8906279..d91dc4e 100644
--- a/src/services.php
+++ b/src/services.php
@@ -5,14 +5,13 @@
namespace StellarWP\Slic;
-use Closure;
use Exception;
/**
- * Returns the `docker-compose` schema parsed from the `slic` files loaded in the current
+ * Returns the `docker compose` schema parsed from the `slic` files loaded in the current
* request.
*
- * @return array The loaded `docker-compose` format files, merged in array format.
+ * @return array The loaded `docker compose` format files, merged in array format.
*/
function stack_schema() {
static $schema;
@@ -45,10 +44,10 @@ function stack_schema() {
}
/**
- * Returns the `service` section of the `docker-compose` format stack files loaded in the request
+ * Returns the `service` section of the `docker compose` format stack files loaded in the request
* for `slic`.
*
- * @return array The `services` section of the loaded `docker-compose` format files.
+ * @return array The `services` section of the loaded `docker compose` format files.
*/
function services_schema() {
$stack_schema = stack_schema();
@@ -69,93 +68,6 @@ function get_services() {
return $services;
}
-/**
- * Returns a list of dependencies for service.
- *
- * Dependencies are read from the stack docker-compose format file in the `links` and
- * `depends_on` sections.
- *
- * @param string $service The name of the service to get the dependencies for.
- *
- * @return array A list of the service dependencies; empty if the service has no
- * dependencies.
- */
-function service_dependencies( string $service ) {
- $services_schema = services_schema();
- $service_links = isset( $services_schema[ $service ]['links'] ) ? $services_schema[ $service ]['links'] : [];
- $service_dependencies = isset( $services_schema[ $service ]['depends_on'] ) ? $services_schema[ $service ]['depends_on'] : [];
-
- return array_merge( $service_links, $service_dependencies );
-}
-
-/**
- * Checks whether a service requires at least one of the listed services in the context of the
- * container stack either by means of `links` or `depends_on` specification.
- *
- * @param string $service The service to check dependencies for.
- * @param string ...$dependencies A list of dependencies to check.
- *
- * @return false Whether the specified service requires at least one of the dependencies or not.
- */
-function service_requires( string $service, ...$dependencies ) {
- if ( empty( $dependencies ) ) {
- return false;
- }
-
- return (bool) count( array_intersect( service_dependencies( $service ), $dependencies ) );
-}
-
-/**
- * Ensures a service is ready to run.
- *
- * @param string $service The service to check.
- *
- * @return void The service readiness is ensured; if required
- * by the service, a callback that should be called
- * after the service is ready is registered in the
- * Services callback stack.
- */
-function ensure_service_ready( string $service ): void {
- $propagate_wordpress_address = static function () {
- // If wordpress isn't running, there's no IP address to propagate.
- if ( ! service_running( 'wordpress' ) ) {
- return;
- }
-
- propagate_ip_address_of_to(
- [ 'wordpress' ],
- [ 'wordpress', 'slic', 'chrome' ],
- [ 'wordpress' => 'wordpress.test' ]
- );
- };
-
- switch ( $service ) {
- case 'wordpress':
- ensure_wordpress_ready();
- services_callback_stack()->add( 'propagate_wp_address', $propagate_wordpress_address );
- services_callback_stack()->add( 'wordpress_notify', '\StellarWP\Slic\service_wordpress_notify' );
- break;
- case 'slic':
- case 'chrome':
- services_callback_stack()->add( 'propagate_wp_address', $propagate_wordpress_address );
- break;
- default:
- break;
- }
-}
-
-/**
- * Ensures a service dependencies are all correctly set up, will
- * exit if not possible.
- *
- * @param string $service The service to ensure the dependencies for.
- *
- * @return void
- */
-function ensure_service_dependencies( string $service ): void {
- ensure_services_running_no_callbacks( service_dependencies( $service ) );
-}
-
/**
* Ensures a list of services is running and returns
* a Closure that should be called to finish setting them up.
@@ -167,30 +79,8 @@ function ensure_service_dependencies( string $service ): void {
* callback stack.
*/
function ensure_services_running( array $services ): void {
- ensure_services_running_no_callbacks( $services );
- services_callback_stack()->call();
-}
-
-/**
- * Ensures a list of services is running and returns
- * a Closure that should be called to finish setting them up.
- *
- * @param array $services A list of services to ensure
- * are running.
- *
- * @return void
- */
-function ensure_services_running_no_callbacks( array $services ): void {
- // Impose an order to make sure dependencies are optimized.
- $order = [ 'db', 'redis', 'chrome', 'slic', 'wordpress' ];
- usort( $services, static function ( $a, $b ) use ( $order ) {
- $a_index = array_search( $a, $order, true );
- $b_index = array_search( $b, $order, true );
-
- return $a_index <=> $b_index;
- } );
foreach ( $services as $service ) {
- ensure_service_running_no_callbacks( $service );
+ ensure_service_running( $service );
}
}
@@ -202,15 +92,18 @@ function ensure_services_running_no_callbacks( array $services ): void {
* @return bool Whether a service is running or not.
*/
function service_running( string $service ) {
- $ps = slic_process()( [ 'ps', '--services', '--filter', '"status=running"' ] );
- $ps_status = $ps( 'status' );
+ $running_services = slic_cache_get( 'running_services' );
- if ( $ps_status !== 0 ) {
- return false;
+ if ( $running_services === null ) {
+ $ps = slic_process()( [ 'ps', '--services', '--filter', '"status=running"' ] );
+ $ps_status = $ps( 'status' );
+ if ( $ps_status !== 0 ) {
+ return false;
+ }
+ $running_services = explode( "\n", $ps( 'string_output' ) );
+ slic_cache_set( 'running_services', $running_services );
}
- $running_services = explode( "\n", $ps( 'string_output' ) );
-
return in_array( $service, $running_services, true );
}
@@ -245,196 +138,20 @@ function get_service_id( string $service ) {
return $status === 0 ? reset( $output ) : null;
}
-/**
- * Returns the IP address of a stack service, if it's up.
- *
- * @param string $service_id The service container ID, e.g. `15148db6f216`.
- *
- * @return string|null The service IP address if the service is up and the IP address
- * could be found, `null` otherwise.
- */
-function get_service_ip_address( string $service_id ) {
- $command = "docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $service_id";
- debug( "Executing command: $command" . PHP_EOL );
- exec( $command, $output, $status );
-
- return $status === 0 ? reset( $output ) : null;
-}
-
-/**
- * Updates a running container /etc/hosts file to add further mappings.
- *
- * Updating a running container `/etc/hosts` file can only be done as the `root` user (UID and GID 0).
- * The `/etc/hosts` file is `rw` (read and write) for the `root` user, and `r` only for all other users.
- * Since the `x` (execute) mode is missing for any user, we cannot use `sed` to update in-place as
- * that requires "swapping" the updated file and that requires execute privileges.
- * The following code reads the current file contents as `root`, updates them, and replaces the file
- * completely using as `root`.
- *
- * @param string $service_id The service docker container ID.
- * @param array $hosts A map from IP addresses to the hostnames that will be added
- * to the container `/etc/hosts` file.
- *
- * @return true To indicate the operation was completed correctly, the function
- * will `exit` with an error, otherwise.
- */
-function add_hosts_to_service( string $service_id, array $hosts ) {
- // Read the current contents of the `/etc/hosts` file.
- $read_command = "docker exec -u '0:0' $service_id bash -c 'cat /etc/hosts'";
- debug( "Executing command: $read_command" . PHP_EOL );
- exec( $read_command, $output, $status );
-
- if ( $status !== 0 ) {
- echo magenta( "Could not get service $service_id /etc/hosts file contents." );
- exit( 1 );
- }
-
- // If a line is already present in the file, do not re-add it.
- $new_lines = array_filter( $output, static function ( $line ) use ( $hosts ) {
- if ( strpos( $line, "\t" ) === false ) {
- return true;
- }
-
- list( $ip, $hostname ) = explode( "\t", $line, 2 );
-
- return ! in_array( $hostname, $hosts, true );
- } );
-
- // The format conventionally used in the `/etc/hosts` file is `\t`.
- $hosts_string = '';
- foreach ( $hosts as $ip_address => $hostname ) {
- $hosts_string .= "$ip_address\t$hostname\n";
- }
-
- $new_lines = implode( "\n", $new_lines ) . "\n" . $hosts_string;
-
- // Write the new lines replacing the `/etc/hosts` file contents.
- $write_command = "docker exec -u '0:0' $service_id bash -c 'echo -e \"$new_lines\\\n\" > /etc/hosts'";
- debug( "Executing command: $write_command" . PHP_EOL );
- exec( $write_command, $output, $status );
-
- if ( $status !== 0 ) {
- echo magenta( "Could not update service $service_id /etc/hosts file contents." );
- exit( 1 );
- }
-
- return true;
-}
-
-/**
- * Updates the `/etc/hosts` file of a list of services to include the IP address of another set of
- * services.
- *
- * @param array $of_services The list of services whose IP address should be propagated.
- * @param array $to_services The list of services whose `/etc/hosts` file should be updated
- * to include the IP addresses to hastname mappings of the previous
- * list.
- * @param array $hostname_map A map from service names to the hostnames they should be
- * mapped to.
- *
- * @return void The method does not return any value and will have the side effect of updating the
- * `/etc/hosts` file of services.
- */
-function propagate_ip_address_of_to( array $of_services, array $to_services, array $hostname_map = [] ) {
- if ( empty( $of_services ) || empty( $to_services ) ) {
- return;
- }
-
- // There might be intersection between source and destination services.
- $all_services = array_unique( array_merge( $of_services, $to_services ) );
- $services_ids = array_combine(
- $all_services,
- array_map( 'StellarWP\Slic\get_service_id', $all_services )
- );
-
- $of_services_ids = array_intersect_key( $services_ids, array_combine( $of_services, array_fill( 0, count( $of_services ), true ) ) );
- $to_services_ids = array_intersect_key( $services_ids, array_combine( $to_services, array_fill( 0, count( $to_services ), true ) ) );
-
- $ip_addresses = array_combine(
- $of_services,
- array_map( 'StellarWP\Slic\get_service_ip_address', $of_services_ids )
- );
-
- $hosts = array_merge( ...array_map( static function ( $service ) use ( $ip_addresses, $hostname_map ) {
- $value = $hostname_map[ $service ] ?? $service;
- $key = $ip_addresses[ $service ];
-
- return [ $key => $value ];
- }, $of_services ) );
-
- array_walk( $to_services_ids, static function ( $service_id ) use ( $hosts ) {
- $service_id && add_hosts_to_service( $service_id, $hosts );
- }, $to_services_ids );
-}
-
-/**
- * Ensures a service is running by ensuring all its pre-conditions and services
- * it depends on.
- *
- * @param string $service The name of the service to ensure running, e.g., `wordpress`.
- * @param array $dependencies The list of services that should be running.
- *
- * @return int The exit status of the command that will ensure the service is running;
- * following UNIX convention, a `0` indicates a success, any other value indicates a
- * failure.
- */
-function ensure_service_running( string $service, array $dependencies = [] ): int {
- $status = ensure_service_running_no_callbacks( $service, $dependencies );
-
- services_callback_stack()->call();
-
- return $status;
-}
-
/**
* Ensures a service is running by ensuring all its pre-conditions and services
* it depends on.
*
- * @param string $service The name of the service to ensure running, e.g., `wordpress`.
- * @param array $dependencies The list of services that should be running.
+ * @param string $service The name of the service to ensure running, e.g., `wordpress`.
*
* @return int The exit status of the command that will ensure the service is running;
* following UNIX convention, a `0` indicates a success, any other value indicates a
* failure.
*/
-function ensure_service_running_no_callbacks( string $service, array $dependencies = [] ): int {
- if ( empty( $dependencies ) && service_running( $service ) ) {
- return 0;
- }
-
- if ( empty( $dependencies ) ) {
- ensure_service_dependencies( $service );
- } else {
- ensure_services_running_no_callbacks( $dependencies );
- }
-
+function ensure_service_running( string $service ): int {
if ( service_running( $service ) ) {
return 0;
}
-
- ensure_service_ready( $service );
-
- $up_status = slic_realtime()( [ 'up', '-d', $service ] );
- service_running( $service );
-
- if ( $up_status !== 0 ) {
- return $up_status;
- }
-
- return 0;
-}
-
-/**
- * Returns the singleton instance of the Services callback stack.
- *
- * @return Callback_Stack The singleton instance of the Services callback stack.
- */
-function services_callback_stack(): Callback_Stack {
- static $callback_stack;
-
- if ( ! $callback_stack instanceof Callback_Stack ) {
- $callback_stack = new Callback_Stack();
- }
-
- return $callback_stack;
+ // Wait for the service to be up|healthy, detached mode is implied.
+ return slic_realtime()( [ 'up', '--wait', $service ] );
}
diff --git a/src/slic.php b/src/slic.php
index f6845a0..81ee284 100644
--- a/src/slic.php
+++ b/src/slic.php
@@ -365,7 +365,7 @@ function php_services() {
/**
* Restart the stack PHP services.
*
- * @param bool $hard Whether to restart the PHP services using the `docker-compose restart` command or by using a
+ * @param bool $hard Whether to restart the PHP services using the `docker compose restart` command or by using a
* tear-down and up again cycle.
*/
function restart_php_services( $hard = false ) {
@@ -379,7 +379,7 @@ function restart_php_services( $hard = false ) {
*
* @param string $service The name of the service to restart, e.g. `wordpress`.
* @param string|null $pretty_name The pretty name to use for the service, or `null` to use the service name.
- * @param bool $hard Whether to restart the service using the `docker-compose restart` command or to use full tear-down
+ * @param bool $hard Whether to restart the service using the `docker compose restart` command or to use full tear-down
* and up again cycle.
*/
function restart_service( $service, $pretty_name = null, $hard = false ) {
@@ -400,7 +400,7 @@ function restart_service( $service, $pretty_name = null, $hard = false ) {
} else {
echo colorize( PHP_EOL . "{$pretty_name} service was not running. Starting it." . PHP_EOL );
$exit_status = ensure_service_running( $service );
- if ( $exit_status !== 0 ) {
+ if ( $exit_status === 0 ) {
echo colorize( "โ
{$pretty_name} service started." . PHP_EOL );
} else {
echo colorize( "โ {$pretty_name} service could not be started." . PHP_EOL );
@@ -422,10 +422,8 @@ function restart_all_services() {
function start_all_services() {
$services = get_services();
foreach ( $services as $service ) {
- ensure_service_running_no_callbacks( $service );
+ ensure_service_running( $service );
}
-
- services_callback_stack()->call();
}
/**
@@ -1219,7 +1217,6 @@ function execute_command_pool( $pool ) {
*/
function cli_command( array $command = [], $requirements = false ) {
if ( $requirements ) {
- ensure_service_running( 'slic' );
ensure_wordpress_ready();
}
@@ -1585,7 +1582,7 @@ function setup_architecture_env() {
putenv( 'SLIC_CHROME_CONTAINER=seleniarm/standalone-chromium:4.1.2-20220227' );
} else {
putenv( 'SLIC_ARCHITECTURE=x86' );
- putenv( 'SLIC_CHROME_CONTAINER=selenium/standalone-chrome:3.141.59-oxygen' );
+ putenv( 'SLIC_CHROME_CONTAINER=selenium/standalone-chrome:3.141.59' );
}
}
diff --git a/src/utils.php b/src/utils.php
index 5af7db0..ce7d53d 100644
--- a/src/utils.php
+++ b/src/utils.php
@@ -200,7 +200,7 @@ function gid() {
*
* On OSes that will handle user ID and group ID mapping at the Docker daemon level, macOS and Windows, the
* `SLIC_UID` and `SLIC_GID` env variables will be set to empty strings.
- * This, in turn, will fill the `user` parameter of the stack services to `user: ":"` that will prompt docker-compose
+ * This, in turn, will fill the `user` parameter of the stack services to `user: ":"` that will prompt docker compose
* to not set the user at all, the wanted behavior on such OSes.
*
* @param bool $reset Whether to re-fetch and reset the user id and group or not.
diff --git a/src/wordpress.php b/src/wordpress.php
index e0b2a42..983535a 100644
--- a/src/wordpress.php
+++ b/src/wordpress.php
@@ -105,196 +105,6 @@ function get_allowed_use_subdirectories(): array {
return [ 'common' ];
}
-/**
- * Ensures WordPress file are correctly unzipped and placed.
- *
- * If a different version of WordPress is already installed, then
- * it will be removed.
- *
- * @param string|null $version The WordPress version to set up
- * the files for.
- *
- * @return bool Always `true` to indicate files are in place.
- */
-function ensure_wordpress_files( $version = null ): bool {
- // By default, download the latest WordPress version.
- $source_url = 'https://wordpress.org/latest.zip';
-
- if ( $version !== null ) {
- // The provided WordPress version will override any env defined version.
- $source_url = "https://wordpress.org/wordpress-$version.zip";
- } else {
- // If set, then use the WordPress version defined by the env.
- $env_wp_version = getenv( 'SLIC_WP_VERSION' );
- $version = $env_wp_version;
- if ( ! empty( $env_wp_version ) ) {
- $source_url = "https://wordpress.org/wordpress-$env_wp_version.zip";
- }
- }
-
- $version = $version ?: 'latest';
-
- debug( "Checking if WordPress version $version is installed and configured ... " . PHP_EOL );
-
- if ( $version === 'latest' ) {
- debug( "Resolving latest version to a semantic version string ..." . PHP_EOL );
- $version = get_wordpress_latest_version();
- }
-
- $wp_root_dir = getenv( 'SLIC_WP_DIR' );
- $version_file = $wp_root_dir . '/wp-includes/version.php';
-
- // Check only if the specified version is not latest.
- if ( is_file( $version_file ) ) {
- include_once $version_file;
-
- // `$wp_version` is globally defined in the `wp-includes/version.php` file.
- if ( isset( $wp_version ) && version_compare( $wp_version, $version ) === 0 ) {
-
- debug( "WordPress current version ($wp_version) matches the requested one ($version)" . PHP_EOL );
-
- return true;
- }
-
- if ( isset( $wp_version ) ) {
- echo "WordPress current version ($wp_version) does not match the requested one ($version), removing WordPress directory ... ";
- }
-
- // Remove the previous version of WordPress.
- quietly_tear_down_stack();
-
- if ( ! rrmdir( $wp_root_dir ) ) {
- magenta( "Failed to remove the previous WordPress directory, try manually." . PHP_EOL );
- exit( 1 );
- }
-
- echo light_cyan( "done" . PHP_EOL );
- } else {
- debug( "Previous WordPress directory not found." . PHP_EOL );
- }
-
- // Tear down the stack to avoid containers from locking the bound directories.
- quietly_tear_down_stack();
-
- // Ensure the destination directory exists.
- if ( ! is_dir( $wp_root_dir ) && ! mkdir( $wp_root_dir, 0755, false ) && ! is_dir( $wp_root_dir ) ) {
- echo magenta( "Failed to create WordPress root directory {$wp_root_dir}" );
- exit( 1 );
- }
-
- // Download WordPress.
- $zip_file = cache( "/wordpress/wordpress-$version.zip" );
- if ( ! is_file( $zip_file ) ) {
- debug( "WordPress zip file $zip_file not found." . PHP_EOL );
-
- $zip_file = download_file( $source_url, $zip_file );
-
- if ( $zip_file === false ) {
- echo magenta( "Failed to download WordPress file from $source_url." );
- exit( 1 );
- }
- }
-
- // Unzip WordPress.
- if ( ! is_file( $wp_root_dir . '/wp-load.php' ) && ! unzip_file( $zip_file, $wp_root_dir ) ) {
- echo magenta( "Failed to extract WordPress file $zip_file to $wp_root_dir." );
- exit( 1 );
- }
-
- return true;
-}
-
-/**
- * Ensures WordPress is correctly configured.
- *
- * @return bool Always `true` to indicate WordPress
- * is set up correctly.
- */
-function ensure_wordpress_configured(): bool {
- $wp_root_dir = getenv( 'SLIC_WP_DIR' );
- $wp_config_file = $wp_root_dir . '/wp-config.php';
-
- if ( is_file( $wp_config_file ) ) {
- debug( "Found $wp_config_file, assuming WordPress already configured." . PHP_EOL );
-
- // If the wp-config.php file already exists, assume WordPress is already configured correctly.
- return true;
- }
-
- $wp_config_sample_file = $wp_root_dir . '/wp-config-sample.php';
-
- if ( ! is_file( $wp_config_sample_file ) ) {
- echo magenta( "Config sample file $wp_config_sample_file not found." );
- exit( 1 );
- }
-
- $wp_config_contents = file_get_contents( $wp_config_sample_file );
-
- if ( empty( $wp_config_contents ) ) {
- echo magenta( "Config sample file $wp_config_sample_file could not be read or is empty." );
- exit( 1 );
- }
-
- debug( "Setting up credentials in $wp_config_file ..." . PHP_EOL );
-
- // Set up the db credentials, rely on the placeholders that come with a default WordPress installation.
- $wp_config_contents = str_replace( [
- 'query( 'SHOW TABLES' );
+ if ( slic_realtime()( cli_command( [ 'core', 'is-installed' ] ) ) === 0 ) {
+ debug( "WordPress is already installed." . PHP_EOL );
- if ( ! $tables instanceof \mysqli_result ) {
- echo magenta( 'Failed to query the WordPress database: ' . mysqli_error( $db ) );
- exit( 1 );
- }
-
- $tables_list = $tables->fetch_all( MYSQLI_NUM );
- if ( ! empty( $tables_list ) ) {
- $default_tables = get_default_tables_list();
- $tables_list = array_column( $tables_list, 0 );
-
- if ( count( array_diff( $default_tables, $tables_list ) ) === 0 ) {
-
- debug( "Default tables found: assuming WordPress is installed." . PHP_EOL );
-
- return true;
- }
+ return true;
}
- debug( "Default tables not found: assuming WordPress is not installed." . PHP_EOL );
-
- $wp_root_dir = getenv( 'SLIC_WP_DIR' );
- $install_file = realpath( $wp_root_dir . '/wp-admin/install.php' );
-
- if ( ! is_file( $install_file ) ) {
- echo magenta( "WordPress installation file $install_file not found." );
+ $install = [
+ 'core',
+ 'install',
+ '--url=http://wordpress.test',
+ '--title=Slic',
+ '--admin_user=admin',
+ '--admin_password=password',
+ '--admin_email=admin@wordpress.test',
+ '--skip-email',
+ ];
+ if ( slic_realtime()( cli_command( $install ) ) !== 0 ) {
+ // There will be debug detailing the issue.
+ echo magenta( "Failed to install WordPress." );
exit( 1 );
}
- // In a separate process, call the installation file directly setting up the expected request vars.
- $code = 'putenv( "DB_HOST=' . get_localhost_db_host() . '" ); ' .
- '$_GET["step"] = 2; ' .
- '$_POST["weblog_title"] = "Slic Test Site"; ' .
- '$_POST["user_name"] = "admin"; ' .
- '$_POST["admin_password"] = "password"; ' .
- '$_POST["admin_password2"] = "password"; ' .
- '$_POST["admin_email"] = "admin@wordpress.test"; ' .
- '$_POST["blog_public"] = 1; ' .
- 'function wp_mail(){ return true; } ' . // It's pluggable, this will mute it.
- 'include "' . $install_file . '";';
-
- $command = escapeshellarg( PHP_BINARY ) . ' -r \'' . $code . '\'';
-
- debug( "Installing WordPress with command $command ... " . PHP_EOL );
-
- exec( $command, $output, $status );
-
- $error_lines = array_filter( $output, static function ( $line ) {
- return strpos( $line, 'Error' ) !== false;
- } );
- $output_has_errors = count( $error_lines );
-
- if ( $status !== 0 || $output_has_errors ) {
- $circa_error_lines = array_map( static function ( $line_number, $line ) use ( $output ) {
- return strip_tags( implode( PHP_EOL, array_slice( $output, $line_number, 10 ) ) );
- }, array_keys( $error_lines ), $error_lines );
- echo magenta( "WordPress installation failed with message(s):" . PHP_EOL . implode( PHP_EOL, $circa_error_lines ) );
+ if ( slic_realtime()( cli_command( [ 'core', 'is-installed' ] ) ) !== 0 ) {
+ echo magenta( "Failed to check WordPress is installed." );
exit( 1 );
}
@@ -448,8 +206,7 @@ function get_wordpress_latest_version(): string {
* @return bool Always `true` to indicate success.
*/
function ensure_wordpress_ready( string $version = null ): bool {
- ensure_wordpress_files( $version );
- ensure_wordpress_configured();
+ ensure_services_running( [ 'slic', 'wordpress' ] );
ensure_wordpress_installed();
return true;