#!/bin/bash # Exit on error, unset var, pipe failure set -euo pipefail ################################################################################################ # Function : Manage the docker command line # Version : See below --version section # Copyright : Copyright (c) 2020 Reid Liu # Copyright : Copyright (c) 2020-2025 Brady Miller # Copyright : Copyright (c) 2025 Matt Summers # Author : Reid Liu # Author : Brady Miller # Author : Matt Summers # License : https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 ################################################################################################# # Increment the version when modify script VERSION="1.0.23" # If the docker is snap or non-snap docker # Setting the container names accordingly get_container_names() { INSANE_DEV_DOCKER="openemr-8-4[_\-]1" EASY_DEV_DOCKER="openemr[_\-]1" COUCHDB_DOCKER="couchdb[_\-]1" MARIADB_DOCKER="mysql[_\-]1" } # Set the container names get_container_names # Initialize ENV_VAR ENV_VAR=' ' # Function to run the devtools script inside the specified container # Usage: run_devtools_in_docker [args...] run_devtools_in_docker() { local container_id="$1" shift # Remove container_id from arguments # DEV_TOOLS is '/root/devtools' # "$@" passes the remaining arguments (devtools command and its args) correctly quoted docker exec -e "${ENV_VAR}" -i "${container_id}" "${DEV_TOOLS}" "$@" } # Function to run an arbitrary shell command string inside the specified container # Usage: run_shell_command_in_docker run_shell_command_in_docker() { local container_id="$1" local command_string="$2" docker exec -i "${container_id}" sh -c "${command_string}" } # Set some constants FIRST_ARG="${1:-}" # define the first parameter, default to empty if not set DEV_TOOLS='/root/devtools' check_docker_compose_install(){ local DOCKER_COMPOSE_CODE=22 # Using an array due to variable expansion for the resulting command # Check for 'docker compose' (plugin syntax) first if docker compose &>/dev/null; then DOCKER_COMPOSE_CMD=(docker compose) # If plugin not found, check for 'docker-compose' (standalone) elif command -v docker-compose &>/dev/null; then DOCKER_COMPOSE_CMD=(docker-compose) else # Neither found, error out. echo "Error: Neither 'docker compose' (plugin) nor 'docker-compose' (standalone) found." >&2 echo "Please ensure Docker Compose is installed correctly." >&2 exit "${DOCKER_COMPOSE_CODE}" fi } # Function to run the determined docker compose command # Usage: run_docker_compose run_docker_compose() { check_docker_compose_install # Ensure the command has been determined if [[ "${#DOCKER_COMPOSE_CMD[@]}" -eq 0 ]]; then echo "Error: Docker Compose command not determined." >&2 exit 1 fi # Execute the stored command with provided arguments "${DOCKER_COMPOSE_CMD[@]}" "$@" } quick_open_a_docker_shell(){ docker exec -w /var/www/localhost/htdocs/openemr -it "${CONTAINER_ID}" sh } quick_open_a_maria_docker_shell(){ docker exec -it "${MARIADB_CONTAINER_ID}" /bin/bash } execute_command_flexible(){ if [[ $# -lt 1 ]]; then echo "Please provide the command." echo "e.g. ${0##*/} [exec|e] \"tail -f /var/log/apache2/error.log\"" echo "e.g. ${0##*/} -d docker_openemr-7-3-redis-312_1 [exec|e] \"tail -f /var/log/apache2/error.log\"" else # Use the function for arbitrary commands run_shell_command_in_docker "${CONTAINER_ID}" "$@" fi } check_docker_log() { docker logs "${CONTAINER_ID}" } check_docker_names() { if [[ $# -eq 1 ]]; then # ARGS: couchdb php fhir mariadb mysql nginx openemr openldap orthanc redis. # specify the name to check local CHECK_NAME="$1" echo '===Check the single Docker Name===' echo ' STATUS NAME' # Capture output, check if empty local matching_container matching_container=$(docker ps -a --format "{{.Status}}\t{{.Names}}"| grep "${CHECK_NAME}" || true) # Keep || true here, and below, to prevent exit during capture if [[ -z "${matching_container}" ]]; then echo "No containers found matching '${CHECK_NAME}'" else echo "${matching_container}" fi else # Show all the docker names. echo '***************************************************************' echo 'Show all the docker names by default.' echo 'Please provide the keyword if you want to check the single one.' echo "e.g $(basename "$0") [docker-names|dn] php" echo '***************************************************************' echo '=======Running Docker Names=======' # Capture output, check if empty local running_containers running_containers=$(docker ps --format "{{.Status}}\t{{.Names}}" | { grep -v NAMES || true; } | sort -n) if [[ -z "${running_containers}" ]]; then echo "No running containers found." else echo ' STATUS NAME' echo "${running_containers}" fi echo '====Other Docker Status Names=====' # Capture output, check if empty local other_containers other_containers=$(docker ps -a --format "{{.Status}}\t{{.Names}}" | grep -v Up || true) if [[ -z "${other_containers}" ]]; then echo "No containers found with other statuses." else echo ' STATUS NAME' echo "${other_containers}" fi fi } restart_couchdb_docker(){ if [[ -z "${COUCHDB_CONTAINER}" ]]; then echo "Unable to find the couchdb docker, so could not restart it" else echo "Restarting couchdb docker" docker restart "${COUCHDB_CONTAINER}" fi } creat_a_backup_snapshot(){ local BACKUP_FILE="$1" local BACKUP_FILE_CODE=20 if [[ $# != 1 ]]; then echo 'Please provide a snapshot name.' echo 'e.g. openemr-cmd [backup-snapshot|bs] example' exit "${BACKUP_FILE_CODE}" else # Use the devtools function run_devtools_in_docker "${CONTAINER_ID}" backup "${BACKUP_FILE}" fi } restore_from_a_snapshot(){ local BACKUP_FILE="$1" local BACKUP_FILE_CODE=21 if [[ $# != 1 ]]; then echo 'Please provide a restore snapshot name.' echo 'e.g. openemr-cmd [restore-snapshot|rs] example' exit "${BACKUP_FILE_CODE}" else # Use the devtools function run_devtools_in_docker "${CONTAINER_ID}" restore "${BACKUP_FILE}" fi } copy_capsule_from_docker_to_host(){ local BACKUP_FILE="$1" local BACKUP_HOST_DIR="${2:-}" #optional parameter, default to empty local BACKUP_FILE_CODE=19 if (( $# != 1 && $# != 2 )); then echo 'Please provide the capsule name.' echo 'e.g. openemr-cmd [get-capsule|gc] example.tgz' echo 'An optional setting is the path to save to. If nothing provided, then will save in current directory.' echo 'e.g. openemr-cmd [get-capsule|gc] example.tgz /path/to/save' exit "${BACKUP_FILE_CODE}" else if [[ -z "${BACKUP_HOST_DIR}" ]]; then docker cp "${CONTAINER_ID}:/snapshots/${BACKUP_FILE}" . else docker cp "${CONTAINER_ID}:/snapshots/${BACKUP_FILE}" "${BACKUP_HOST_DIR}/" fi fi } copy_capsule_from_host_to_docker(){ # Need a capsule parameter local BACKUP_FILE="$1" local CP_CAP_DIR_DKR_CODE=15 local BACKUP_FILE_CODE=18 if [[ $# != 1 ]]; then echo 'Please provide the capsule file name (including path if applicable).' echo 'e.g. openemr-cmd [put-capsule|pc] example.tgz' exit "${BACKUP_FILE_CODE}" else if ! ls "${BACKUP_FILE}" &>/dev/null; then echo 'Please check whether the capsule file exists or not' exit "${CP_CAP_DIR_DKR_CODE}" else docker cp "${BACKUP_FILE}" "${CONTAINER_ID}:/snapshots/" fi fi } ensure_current_ver_with_upgrade_ver(){ # Need a version parameter local UPGRADE_FROM_VERSION="$1" local BACKUP_FILE_CODE=22 if [[ $# != 1 ]]; then echo 'Please provide the OpenEMR version to upgrade database from.' echo 'e.g. openemr-cmd [ensure-version|ev] 5.0.2' exit "${BACKUP_FILE_CODE}" else # Use the devtools function run_devtools_in_docker "${CONTAINER_ID}" upgrade "${UPGRADE_FROM_VERSION}" fi } change_db_character_set_and_collation(){ local CHARACTER_SET_COLLATION_CODE=17 if [[ $# != 2 ]]; then echo 'Please provide two parameters.' echo 'e.g. openemr-cmd [encoding-collation|ec] utf8mb4 utf8mb4_general_ci' echo ' openemr-cmd [encoding-collation|ec] utf8mb4 utf8mb4_unicode_ci' echo ' openemr-cmd [encoding-collation|ec] utf8mb4 utf8mb4_vietnamese_ci' echo ' openemr-cmd [encoding-collation|ec] utf8 utf8_general_ci' exit "${CHARACTER_SET_COLLATION_CODE}" else # Use the devtools function, passing both arguments run_devtools_in_docker "${CONTAINER_ID}" change-encoding-collation "$1" "$2" fi } setup-client-cert(){ local CERT_PACKAGE="$1" local CERT_PACKAGE_CODE=30 if [[ $# != 1 ]]; then echo 'Please provide a certificate package name.' echo 'e.g. openemr-cmd [scc|setup-client-cert] sll' exit "${CERT_PACKAGE_CODE}" else # Use the devtools function run_devtools_in_docker "${CONTAINER_ID}" setup-client-cert "${CERT_PACKAGE}" fi } put-client-cert(){ # Need a capsule parameter local CERT_PACKAGE_FILE="$1" local PUT_CLIENT_CERT_CODE=32 local CERT_PACKAGE_FILE_CODE=31 if [[ $# != 1 ]]; then echo 'Please provide the certificate package file name (including path if applicable).' echo 'e.g. openemr-cmd [pcc|put-client-cert] sll.zip' exit "${CERT_PACKAGE_FILE_CODE}" else if ! ls "${CERT_PACKAGE_FILE}" &>/dev/null; then echo 'Please check whether the certificate package file exists or not' exit "${PUT_CLIENT_CERT_CODE}" else docker cp "${CERT_PACKAGE_FILE}" "${CONTAINER_ID}:/certs/" fi fi } import-random-patients(){ # Use the devtools function, passing all arguments ($@) ENV_VAR="OPENEMR_ENABLE_CCDA_IMPORT=1" run_devtools_in_docker "${CONTAINER_ID}" import-random-patients "$@" } register-oauth2-client-demo(){ # Use the devtools function, passing all arguments ($@) run_devtools_in_docker "${CONTAINER_ID}" register-oauth2-client-demo "$@" } register-oauth2-client(){ # Use the devtools function, passing all arguments ($@) run_devtools_in_docker "${CONTAINER_ID}" register-oauth2-client "$@" } set-swagger-to-multisite(){ # Use the devtools function, passing all arguments ($@) run_devtools_in_docker "${CONTAINER_ID}" set-swagger-to-multisite "$@" } set-webroot(){ local sed_command if (( $# == 1 )); then # assume the openemr parameter was given, so set openemr webroot echo "changing webroot to openemr" sed_command="sed -i 's@^DocumentRoot /var/www/localhost/htdocs.*@DocumentRoot /var/www/localhost/htdocs@g' /etc/apache2/conf.d/openemr.conf" else # set to blank, so set blank webroot echo "changing webroot to blank" sed_command="sed -i 's@^DocumentRoot /var/www/localhost/htdocs.*@DocumentRoot /var/www/localhost/htdocs/openemr@g' /etc/apache2/conf.d/openemr.conf" fi # Use the function for arbitrary commands run_shell_command_in_docker "${CONTAINER_ID}" "${sed_command}" # restart the docker echo "restarting openemr docker so the apache configuration change will take effect" docker restart "${CONTAINER_ID}" } docker-pull-image(){ local docker_images docker_images=$(docker ps --format "table {{.Image}}") local IMAGE RESP for IMAGE in ${docker_images}; do if [[ "${IMAGE}" != "IMAGE" ]]; then # Use -r with read read -r -e -p "Do you wish to pull ${IMAGE} ? (y) " RESP if [[ "${RESP,,}" = y ]]; then docker pull "${IMAGE}" else echo "Skipping ${IMAGE}" fi fi done } USAGE_EXIT_CODE=13 VERSION_EXIT_CODE=14 FINAL_EXIT_CODE=0 # Confirm the docker install or not. DOCKER_CODE=16 if ! command -v docker &>/dev/null; then echo "Please check docker install or not." exit "${DOCKER_CODE}" fi # Script usage. if [[ $# -eq 0 || "${FIRST_ARG}" = '--help' || "${FIRST_ARG}" = '-h' ]]; then echo echo "Usage: ${0##*/} COMMAND [ARGS]" echo "Usage: ${0##*/} -d COMMAND [ARGS]" echo "Options:" echo " -h, --help Show the commands usage" echo " -v, --version Show the openemr-cmd command version" echo " -d Specify the docker id or name to execute commands" echo 'Commands:' echo 'docker-management:' echo " up Execute: docker-compose up -d" echo " down Execute: docker-compose down -v" echo " start Execute: docker-compose start" echo " stop Execute: docker-compose stop" echo " s, shell Open a docker shell quickly" echo " ms, maria-shell Open a maria docker shell quickly (only works in the easy dev environment)" echo " e, exec Execute commands outside docker" echo " dl, docker-log To check docker log" echo " dn, docker-names To check docker the running docker names" echo " dpi, docker-pull-image Prompt to pull docker image" echo 'php-management:' echo " bt, build-themes Make changes to any files on your local file system" echo " pl, php-log To check PHP error logs" echo " pr, psr12-report To create a report of PSR12 code styling issues" echo " pf, psr12-fix To fix PSR12 code styling issues" echo " ltr, lint-themes-report To create a report of theme styling issues" echo " ltf, lint-themes-fix To fix theme styling issues" echo " ljr, lint-javascript-report To create a report of javascript styling issues" echo " ljf, lint-javascript-fix To fix javascript styling issues" echo " pp, php-parserror To check PHP parsing errors" echo " rd, rector-dry-run To dry-run Rector changes" echo " rp, rector-process To process Rector changes" echo " pst, phpstan To run PHPStan" echo " xl, xdebug-log To check xdebug log" echo " lxp, list-xdebug-profiles To list xdebug profiles" echo 'test-management:' echo " ut, unit-test To run php unit testing" echo " jut, javascript-unit-test To run javascript unit testing" echo " jrb, jut-reports-build To build javascript unit testing reports browser user interface" echo " at, api-test To run api testing" echo " et, e2e-test To run e2e testing" echo " st, services-test To run services testing" echo " ft, fixtures-test To run fixtures testing" echo " vt, validators-test To run validators testing" echo " ct, controllers-test To run controllers testing" echo " ctt, common-test To run common testing" echo 'sweep-management:' echo " cs, clean-sweep To run the entire dev tool suite" echo " cst, clean-sweep-tests To run only all the automated tests" echo 'reset-management:' echo " dr, dev-reset To reset OpenEMR only" echo " di, dev-install To install OpenEMR (reset needs to be run prior)" echo " dri, dev-reset-install To reset and reinstall OpenEMR" echo " drid, dev-reset-install-demodata To reset and reinstall OpenEMR with demo data" echo 'backup-management:' echo " bs, backup-snapshot Create a backup snapshot" echo " rs, restore-snapshot Restore from a snapshot" echo " ls, list-snapshots To list the snapshots" echo " lc, list-capsules List the capsules" echo " gc, get-capsule Copy the capsule from the docker to your host directory" echo " pc, put-capsule Copy the capsule into the docker" echo 'ssl-management:' echo " fh, force-https Force https" echo " ufh, un-force-https Removing forcing of https" echo " ossc, on-self-signed-cert Toggle on self signed certificates (on by default)" echo " scc, setup-client-cert Turn on client based cert with designated package" echo " lcc, list-client-certs To list the certificate packages" echo " pcc, put-client-cert To copy certificate package into the docker" echo " ss, sql-ssl Use testing sql ssl CA cert" echo " sso, sql-ssl-off Remove testing sql ssl CA cert" echo " ssc, sql-ssl-client Use testing sql ssl client certs" echo " ssco, sql-ssl-client-off Remove testing sql ssl client certs" echo " css, couchdb-ssl Use testing couchdb ssl CA cert" echo " cso, couchdb-ssl-off Remove testing couchdb ssl CA cert" echo " csc, couchdb-ssl-client Use testing couchdb ssl client certs" echo " csco, couchdb-ssl-client-off Remove testing couchdb ssl client certs" echo " lss, ldap-ssl Use testing ldap ssl CA cert" echo " lso, ldap-ssl-off Remove testing ldap ssl CA cert" echo " lsc, ldap-ssl-client Use testing ldap ssl client certs" echo " lsco, ldap-ssl-client-off Remove testing ldap ssl client certs" echo 'multisite-management:' echo " lm, list-multisites List multisites" echo " swtm, set-swagger-to-multisite Direct swagger api testing suite to use a multisite " echo " gmb, generate-multisite-bank Create bank of multisites cloned from default " echo " em, enable-multisite Turn on support for multisite in setup.php" echo " dm, disable-multisite Turn off support for multisite in setup.php" echo 'api-management:' echo " bad, build-api-docs Build and place api documentation/configuration for swagger" echo " roc, register-oauth2-client Register oauth2 client (returns client id/secret)" echo " rocd, register-oauth2-client-demo Register oauth2 client (returns client id/secret) on online demo" echo " swtm, set-swagger-to-multisite Direct swagger api testing suite to use a multisite " echo 'computational-health-informatics:' echo " irp, import-random-patients Create and import random patients " echo " gmb, generate-multisite-bank Create bank of multisites cloned from default " echo 'webroot-management:' echo " cwb, change-webroot-blank Change webroot to be blank (this is default setting of environment)" echo " cwo, change-webroot-openemr Change webroot to be openemr" echo 'others:' echo " ev, ensure-version Upgrade OpenEMR from specified old version to current version" echo " el, enable-ldap Turn on support for LDAP - login credentials are admin:admin" echo " dld, disable-ldap Turn off support for LDAP - standard login credentials" echo " ec, encoding-collation Change the database character set and collation" exit "${USAGE_EXIT_CODE}" elif [[ "${FIRST_ARG}" = '--version' || "${FIRST_ARG}" = '-v' ]]; then echo "openemr-cmd ${VERSION}" exit "${VERSION_EXIT_CODE}" fi # Specify the docker id/name to execute the commands. # Default to insane dev docker, if exists, otherwise easy dev docker. # Try to find the insane dev docker ID directly if insane_id=$(docker ps --filter "name=${INSANE_DEV_DOCKER}" --format "{{.ID}}" | head -n 1); [[ -n "${insane_id}" ]]; then CONTAINER_ID="${insane_id}" # Try to find the easy dev docker ID directly elif easy_id=$(docker ps --filter "name=${EASY_DEV_DOCKER}" --format "{{.ID}}" | head -n 1); [[ -n "${easy_id}" ]]; then CONTAINER_ID="${easy_id}" else # Neither container found running, set CONTAINER_ID to empty. # The script's later logic handles the -d flag or errors if no container is specified. CONTAINER_ID="" fi # override the default container setting if supplied via the -d parameter # (also removing no longer needed parameters via shift) CHANGE_CONTAINER_CODE=25 if [[ "${FIRST_ARG}" = '-d' ]]; then if (( $# < 3 )); then echo 'Please provide a docker id/name when using -d parameter.' echo 'e.g. openemr-cmd -d docker_openemr-7-3-redis-312_1 dl' exit "${CHANGE_CONTAINER_CODE}" fi CONTAINER_ID="$2" FIRST_ARG="$3" shift 3 else shift fi #collect the couchdb docker name # Use docker ps --filter and --format for efficiency and robustness couchdb_id=$(docker ps --filter "name=${COUCHDB_DOCKER}" --format "{{.ID}}" | head -n 1) COUCHDB_CONTAINER="${couchdb_id:-}" # Set to empty if not found # Collect the mariadb container id # Use docker ps --filter and --format for efficiency and robustness mariadb_id=$(docker ps --filter "name=${MARIADB_DOCKER}" --format "{{.ID}}" | head -n 1) MARIADB_CONTAINER_ID="${mariadb_id:-}" # Set to empty if not found # Check if a target container ID was determined or provided before proceeding with commands that need it # (Allow proceeding if the command doesn't require a container, like up, down, start, stop, --help, --version) case "${FIRST_ARG}" in up|down|start|stop|--help|-h|--version|-v) # These commands don't necessarily need a running container ID determined here ;; *) # All other commands likely need a CONTAINER_ID # Check if CONTAINER_ID is empty AND -d wasn't the *original* first arg if [[ -z "${CONTAINER_ID}" && "${FIRST_ARG}" != '-d' ]]; then echo "Error: Could not automatically determine target OpenEMR container (tried '${INSANE_DEV_DOCKER}' and '${EASY_DEV_DOCKER}')." >&2 echo "Use -d to specify the target container." >&2 exit 1 fi # If -d was used, CONTAINER_ID was set in the parameter parsing block ;; esac # See how we were called. # For the shift usage, it used to cover the insane env. case "${FIRST_ARG}" in up) run_docker_compose up -d ;; down) run_docker_compose down -v ;; stop) run_docker_compose stop ;; start) run_docker_compose start ;; s|shell) quick_open_a_docker_shell ;; e|exec) execute_command_flexible "$@" ;; dl|docker-log) check_docker_log ;; dn|docker-names) check_docker_names "$@" ;; dpi|docker-pull-image) docker-pull-image "$@" ;; bs|backup-snapshot) creat_a_backup_snapshot "$@" ;; rs|restore-snapshot) restore_from_a_snapshot "$@" restart_couchdb_docker ;; gc|get-capsule) copy_capsule_from_docker_to_host "$@" ;; pc|put-capsule) copy_capsule_from_host_to_docker "$@" ;; ev|ensure-version) ensure_current_ver_with_upgrade_ver "$@" ;; ec|encoding-collation) change_db_character_set_and_collation "$@" ;; scc|setup-client-cert) setup-client-cert "$@" ;; pcc|put-client-cert) put-client-cert "$@" ;; irp|import-random-patients) import-random-patients "$@" ;; rocd|register-oauth2-client-demo) register-oauth2-client-demo "$@" ;; roc|register-oauth2-client) register-oauth2-client "$@" ;; swtm|set-swagger-to-multisite) set-swagger-to-multisite "$@" ;; cwb|change-webroot-blank) set-webroot ;; cwo|change-webroot-openemr) set-webroot openemr ;; ms|maria-shell) quick_open_a_maria_docker_shell ;; bt) run_devtools_in_docker "${CONTAINER_ID}" build-themes ;; pl) run_devtools_in_docker "${CONTAINER_ID}" php-log ;; pr) run_devtools_in_docker "${CONTAINER_ID}" psr12-report ;; pf) run_devtools_in_docker "${CONTAINER_ID}" psr12-fix ;; ltr) run_devtools_in_docker "${CONTAINER_ID}" lint-themes-report ;; ltf) run_devtools_in_docker "${CONTAINER_ID}" lint-themes-fix ;; ljr) run_devtools_in_docker "${CONTAINER_ID}" lint-javascript-report ;; ljf) run_devtools_in_docker "${CONTAINER_ID}" lint-javascript-fix ;; pp) run_devtools_in_docker "${CONTAINER_ID}" php-parserror ;; rd) run_devtools_in_docker "${CONTAINER_ID}" rector-dry-run ;; rp) run_devtools_in_docker "${CONTAINER_ID}" rector-process ;; pst) run_devtools_in_docker "${CONTAINER_ID}" phpstan ;; ut) run_devtools_in_docker "${CONTAINER_ID}" unit-test ;; jut) run_devtools_in_docker "${CONTAINER_ID}" javascript-unit-test ;; jrb) run_devtools_in_docker "${CONTAINER_ID}" jut-reports-build ;; at) run_devtools_in_docker "${CONTAINER_ID}" api-test ;; et) run_devtools_in_docker "${CONTAINER_ID}" e2e-test ;; st) run_devtools_in_docker "${CONTAINER_ID}" services-test ;; ft) run_devtools_in_docker "${CONTAINER_ID}" fixtures-test ;; vt) run_devtools_in_docker "${CONTAINER_ID}" validators-test ;; ct) run_devtools_in_docker "${CONTAINER_ID}" controllers-test ;; ctt) run_devtools_in_docker "${CONTAINER_ID}" common-test ;; cs) run_devtools_in_docker "${CONTAINER_ID}" clean-sweep ;; cst) run_devtools_in_docker "${CONTAINER_ID}" clean-sweep-tests ;; dr) run_devtools_in_docker "${CONTAINER_ID}" dev-reset restart_couchdb_docker ;; di) run_devtools_in_docker "${CONTAINER_ID}" dev-install restart_couchdb_docker ;; dri) run_devtools_in_docker "${CONTAINER_ID}" dev-reset-install restart_couchdb_docker ;; drid) run_devtools_in_docker "${CONTAINER_ID}" dev-reset-install-demodata restart_couchdb_docker ;; ls) run_devtools_in_docker "${CONTAINER_ID}" list-snapshots ;; lc) run_devtools_in_docker "${CONTAINER_ID}" list-capsules ;; em) run_devtools_in_docker "${CONTAINER_ID}" enable-multisite ;; dm) run_devtools_in_docker "${CONTAINER_ID}" disable-multisite ;; fh) run_devtools_in_docker "${CONTAINER_ID}" force-https ;; ufh) run_devtools_in_docker "${CONTAINER_ID}" un-force-https ;; ossc) run_devtools_in_docker "${CONTAINER_ID}" on-self-signed-cert ;; lcc) run_devtools_in_docker "${CONTAINER_ID}" list-client-certs ;; ss) run_devtools_in_docker "${CONTAINER_ID}" sql-ssl ;; sso) run_devtools_in_docker "${CONTAINER_ID}" sql-ssl-off ;; ssc) run_devtools_in_docker "${CONTAINER_ID}" sql-ssl-client ;; ssco) run_devtools_in_docker "${CONTAINER_ID}" sql-ssl-client-off ;; css) run_devtools_in_docker "${CONTAINER_ID}" couchdb-ssl ;; cso) run_devtools_in_docker "${CONTAINER_ID}" couchdb-ssl-off ;; csc) run_devtools_in_docker "${CONTAINER_ID}" couchdb-ssl-client ;; csco) run_devtools_in_docker "${CONTAINER_ID}" couchdb-ssl-client-off ;; lss) run_devtools_in_docker "${CONTAINER_ID}" ldap-ssl ;; lso) run_devtools_in_docker "${CONTAINER_ID}" ldap-ssl-off ;; lsc) run_devtools_in_docker "${CONTAINER_ID}" ldap-ssl-client ;; lsco) run_devtools_in_docker "${CONTAINER_ID}" ldap-ssl-client-off ;; gmb|generate-multisite-bank) # Pass remaining arguments ($@) correctly quoted to the devtools function run_devtools_in_docker "${CONTAINER_ID}" generate-multisite-bank "$@" ;; el) run_devtools_in_docker "${CONTAINER_ID}" enable-ldap ;; dld) run_devtools_in_docker "${CONTAINER_ID}" disable-ldap ;; xl) run_devtools_in_docker "${CONTAINER_ID}" xdebug-log ;; lxp) run_devtools_in_docker "${CONTAINER_ID}" list-xdebug-profiles ;; bad) run_devtools_in_docker "${CONTAINER_ID}" build-api-docs ;; lm) run_devtools_in_docker "${CONTAINER_ID}" list-multisites ;; *) # Default case: assume it's a devtools command run_devtools_in_docker "${CONTAINER_ID}" "${FIRST_ARG}" "$@" ;; esac exit "${FINAL_EXIT_CODE}"