Skip to content

Instantly share code, notes, and snippets.

@stevobengtson
Last active February 7, 2023 22:31
Show Gist options
  • Save stevobengtson/7b6e4d8f4a47e21c8f13b3e61418af91 to your computer and use it in GitHub Desktop.
Save stevobengtson/7b6e4d8f4a47e21c8f13b3e61418af91 to your computer and use it in GitHub Desktop.
Sail script to use in Symfony projects
#!/usr/bin/env bash
UNAMEOUT="$(uname -s)"
# Verify operating system is supported...
case "${UNAMEOUT}" in
Linux*) MACHINE=linux;;
Darwin*) MACHINE=mac;;
*) MACHINE="UNKNOWN"
esac
if [ "$MACHINE" == "UNKNOWN" ]; then
echo "Unsupported operating system [$(uname -s)]. LTW supports macOS, Linux, and Windows (WSL2)." >&2
exit 1
fi
# Determine if stdout is a terminal...
if test -t 1; then
# Determine if colors are supported...
ncolors=$(tput colors)
if test -n "$ncolors" && test "$ncolors" -ge 8; then
BOLD="$(tput bold)"
YELLOW="$(tput setaf 3)"
GREEN="$(tput setaf 2)"
NC="$(tput sgr0)"
fi
fi
# Function that prints the available commands...
function display_help {
echo "LTW Docker"
echo
echo "${YELLOW}Usage:${NC}" >&2
echo " ltw COMMAND [options] [arguments]"
echo
echo "Unknown commands are passed to the docker-compose binary."
echo
echo "${YELLOW}docker-compose Commands:${NC}"
echo " ${GREEN}ltw up${NC} Start the application"
echo " ${GREEN}ltw up -d${NC} Start the application in the background"
echo " ${GREEN}ltw stop${NC} Stop the application"
echo " ${GREEN}ltw restart${NC} Restart the application"
echo " ${GREEN}ltw ps${NC} Display the status of all containers"
echo
echo "${YELLOW}Console Commands:${NC}"
echo " ${GREEN}ltw console ...${NC} Run an Console command"
echo " ${GREEN}ltw console queue:work${NC}"
echo
echo "${YELLOW}PHP Commands:${NC}"
echo " ${GREEN}ltw php ...${NC} Run a snippet of PHP code"
echo " ${GREEN}ltw php -v${NC}"
echo
echo "${YELLOW}Composer Commands:${NC}"
echo " ${GREEN}ltw composer ...${NC} Run a Composer command"
echo " ${GREEN}ltw composer require laravel/sanctum${NC}"
echo
echo "${YELLOW}Node Commands:${NC}"
echo " ${GREEN}ltw node ...${NC} Run a Node command"
echo " ${GREEN}ltw node --version${NC}"
echo
echo "${YELLOW}NPM Commands:${NC}"
echo " ${GREEN}ltw npm ...${NC} Run a npm command"
echo " ${GREEN}ltw npx${NC} Run a npx command"
echo " ${GREEN}ltw npm run prod${NC}"
echo
echo "${YELLOW}Yarn Commands:${NC}"
echo " ${GREEN}ltw yarn ...${NC} Run a Yarn command"
echo " ${GREEN}ltw yarn run prod${NC}"
echo
echo "${YELLOW}Database Commands:${NC}"
echo " ${GREEN}ltw mysql${NC} Start a MySQL CLI session within the 'mysql' container"
echo " ${GREEN}ltw mariadb${NC} Start a MySQL CLI session within the 'mariadb' container"
echo " ${GREEN}ltw psql${NC} Start a PostgreSQL CLI session within the 'pgsql' container"
echo " ${GREEN}ltw redis${NC} Start a Redis CLI session within the 'redis' container"
echo
echo "${YELLOW}Debugging:${NC}"
echo " ${GREEN}ltw debug ...${NC} Run an Console command in debug mode"
echo " ${GREEN}ltw debug queue:work${NC}"
echo
echo "${YELLOW}Running Tests:${NC}"
echo " ${GREEN}ltw test${NC} Run the PHPUnit tests via the Console test command"
echo " ${GREEN}ltw phpunit ...${NC} Run PHPUnit"
echo " ${GREEN}ltw pest ...${NC} Run Pest"
echo " ${GREEN}ltw pint ...${NC} Run Pint"
echo " ${GREEN}ltw dusk${NC} Run the Dusk tests (Requires the laravel/dusk package)"
echo " ${GREEN}ltw dusk:fails${NC} Re-run previously failed Dusk tests (Requires the laravel/dusk package)"
echo
echo "${YELLOW}Container CLI:${NC}"
echo " ${GREEN}ltw shell${NC} Start a shell session within the application container"
echo " ${GREEN}ltw bash${NC} Alias for 'ltw shell'"
echo " ${GREEN}ltw root-shell${NC} Start a root shell session within the application container"
echo " ${GREEN}ltw root-bash${NC} Alias for 'ltw root-shell'"
echo " ${GREEN}ltw tinker${NC} Start a new PSYSH session"
echo
echo "${YELLOW}Sharing:${NC}"
echo " ${GREEN}ltw share${NC} Share the application publicly via a temporary URL"
echo
echo "${YELLOW}Binaries:${NC}"
echo " ${GREEN}ltw bin ...${NC} Run Composer binary scripts from the vendor/bin directory"
echo
exit 1
}
# Proxy the "help" command...
if [ $# -gt 0 ]; then
if [ "$1" == "help" ] || [ "$1" == "-h" ] || [ "$1" == "-help" ] || [ "$1" == "--help" ]; then
display_help
fi
else
display_help
fi
# Source the ".env" file so Symfony's environment variables are available...
if [ ! -z "$APP_ENV" ] && [ -f ./.env.$APP_ENV ]; then
source ./.env.$APP_ENV;
elif [ -f ./.env ]; then
source ./.env;
fi
# Define environment variables...
export APP_PORT=${APP_PORT:-80}
export APP_SERVICE=${APP_SERVICE:-"app"}
export DB_PORT=${DB_PORT:-3306}
export LTW_FILES=${LTW_FILES:-""}
export LTW_SHARE_DASHBOARD=${LTW_SHARE_DASHBOARD:-4040}
export LTW_SHARE_SERVER_HOST=${LTW_SHARE_SERVER_HOST:-"localhost"}
export LTW_SHARE_SERVER_PORT=${LTW_SHARE_SERVER_PORT:-8000}
export LTW_SHARE_SUBDOMAIN=${LTW_SHARE_SUBDOMAIN:-""}
export LTW_SHARE_DOMAIN=${LTW_SHARE_DOMAIN:-""}
# Function that outputs ltw is not running...
function ltw_is_not_running {
echo "${BOLD}ltw is not running.${NC}" >&2
echo "" >&2
echo "${BOLD}You may start ltw using the following commands:${NC} './bin/ltw up' or './bin/ltw up -d'" >&2
exit 1
}
# Define Docker Compose command prefix...
docker compose &> /dev/null
if [ $? == 0 ]; then
DOCKER_COMPOSE=(docker compose)
else
DOCKER_COMPOSE=(docker-compose)
fi
if [ -n "$LTW_FILES" ]; then
# Convert LTW_FILES to an array...
IFS=':' read -ra LTW_FILES <<< "$LTW_FILES"
for FILE in "${LTW_FILES[@]}"; do
if [ -f "$FILE" ]; then
DOCKER_COMPOSE+=(-f "$FILE")
else
echo "${BOLD}Unable to find Docker Compose file: '${FILE}'${NC}" >&2
exit 1
fi
done
fi
EXEC="yes"
if [ -z "$LTW_SKIP_CHECKS" ]; then
# Ensure that Docker is running...
if ! docker info > /dev/null 2>&1; then
echo "${BOLD}Docker is not running.${NC}" >&2
exit 1
fi
# Determine if ltw is currently up...
if "${DOCKER_COMPOSE[@]}" ps "$APP_SERVICE" 2>&1 | grep 'Exit\|exited'; then
echo "${BOLD}Shutting down old ltw processes...${NC}" >&2
"${DOCKER_COMPOSE[@]}" down > /dev/null 2>&1
EXEC="no"
elif [ -z "$("${DOCKER_COMPOSE[@]}" ps -q)" ]; then
EXEC="no"
fi
fi
ARGS=()
# Proxy PHP commands to the "php" binary on the application container...
if [ "$1" == "php" ]; then
shift 1
if [ "$EXEC" == "yes" ]; then
ARGS+=(exec)
[ ! -t 0 ] && ARGS+=(-T)
ARGS+=("$APP_SERVICE" "php" "$@")
else
ltw_is_not_running
fi
# Proxy vendor binary commands on the application container...
elif [ "$1" == "bin" ]; then
shift 1
if [ "$EXEC" == "yes" ]; then
ARGS+=(exec)
[ ! -t 0 ] && ARGS+=(-T)
ARGS+=("$APP_SERVICE" ./vendor/bin/"$@")
else
ltw_is_not_running
fi
# Proxy Composer commands to the "composer" binary on the application container...
elif [ "$1" == "composer" ]; then
shift 1
if [ "$EXEC" == "yes" ]; then
ARGS+=(exec)
[ ! -t 0 ] && ARGS+=(-T)
ARGS+=("$APP_SERVICE" "composer" "$@")
else
ltw_is_not_running
fi
# Proxy Console commands to the "console" binary on the application container...
elif [ "$1" == "console" ] || [ "$1" == "con" ]; then
shift 1
if [ "$EXEC" == "yes" ]; then
ARGS+=(exec)
[ ! -t 0 ] && ARGS+=(-T)
ARGS+=("$APP_SERVICE" php bin/console "$@")
else
ltw_is_not_running
fi
# Proxy the "debug" command to the "php console" binary on the application container with xdebug enabled...
elif [ "$1" == "debug" ]; then
shift 1
if [ "$EXEC" == "yes" ]; then
ARGS+=(exec -e XDEBUG_SESSION=1)
[ ! -t 0 ] && ARGS+=(-T)
ARGS+=("$APP_SERVICE" php bin/console "$@")
else
ltw_is_not_running
fi
# Proxy the "test" or "phpunit" command to the "php bin/phpunit" command...
elif [ "$1" == "test" ] || [ "$1" == "phpunit" ]; then
shift 1
if [ "$EXEC" == "yes" ]; then
ARGS+=(exec)
[ ! -t 0 ] && ARGS+=(-T)
ARGS+=("$APP_SERVICE" php bin/phpunit "$@")
else
ltw_is_not_running
fi
# Initiate a PSYSH session within the application container...
elif [ "$1" == "tinker" ] ; then
shift 1
if [ "$EXEC" == "yes" ]; then
ARGS+=(exec)
[ ! -t 0 ] && ARGS+=(-T)
ARGS+=("$APP_SERVICE" php vendor/bin/psysh)
else
ltw_is_not_running
fi
# Proxy Node commands to the "node" binary on the application container...
elif [ "$1" == "node" ]; then
shift 1
if [ "$EXEC" == "yes" ]; then
ARGS+=(exec)
[ ! -t 0 ] && ARGS+=(-T)
ARGS+=("$APP_SERVICE" node "$@")
else
ltw_is_not_running
fi
# Proxy NPM commands to the "npm" binary on the application container...
elif [ "$1" == "npm" ]; then
shift 1
if [ "$EXEC" == "yes" ]; then
ARGS+=(exec)
[ ! -t 0 ] && ARGS+=(-T)
ARGS+=("$APP_SERVICE" npm "$@")
else
ltw_is_not_running
fi
# Proxy NPX commands to the "npx" binary on the application container...
elif [ "$1" == "npx" ]; then
shift 1
if [ "$EXEC" == "yes" ]; then
ARGS+=(exec)
[ ! -t 0 ] && ARGS+=(-T)
ARGS+=("$APP_SERVICE" npx "$@")
else
ltw_is_not_running
fi
# Proxy YARN commands to the "yarn" binary on the application container...
elif [ "$1" == "yarn" ]; then
shift 1
if [ "$EXEC" == "yes" ]; then
ARGS+=(exec)
[ ! -t 0 ] && ARGS+=(-T)
ARGS+=("$APP_SERVICE" yarn "$@")
else
ltw_is_not_running
fi
# Initiate a MySQL or MariaDB CLI terminal session within the "database" container...
elif [ "$1" == "mysql" ] || [ "$1" == "mariadb" ]; then
shift 1
if [ "$EXEC" == "yes" ]; then
ARGS+=(exec)
[ ! -t 0 ] && ARGS+=(-T)
ARGS+=(database bash -c)
ARGS+=("MYSQL_PWD=\${MYSQL_PASSWORD} mysql -u \${MYSQL_USER} \${MYSQL_DATABASE}")
else
ltw_is_not_running
fi
# Initiate a PostgreSQL CLI terminal session within the "database" container...
elif [ "$1" == "psql" ]; then
shift 1
if [ "$EXEC" == "yes" ]; then
ARGS+=(exec)
[ ! -t 0 ] && ARGS+=(-T)
ARGS+=(database bash -c)
ARGS+=("PGPASSWORD=\${PGPASSWORD} psql -U \${POSTGRES_USER} \${POSTGRES_DB}")
else
ltw_is_not_running
fi
# Initiate a Bash shell within the application container...
elif [ "$1" == "shell" ] || [ "$1" == "bash" ]; then
shift 1
if [ "$EXEC" == "yes" ]; then
ARGS+=(exec)
[ ! -t 0 ] && ARGS+=(-T)
ARGS+=("$APP_SERVICE" bash "$@")
else
ltw_is_not_running
fi
# Initiate a root user Bash shell within the application container...
elif [ "$1" == "root-shell" ] || [ "$1" == "root-bash" ]; then
shift 1
if [ "$EXEC" == "yes" ]; then
ARGS+=(exec)
[ ! -t 0 ] && ARGS+=(-T)
ARGS+=("$APP_SERVICE" bash "$@")
else
ltw_is_not_running
fi
# Initiate a Redis CLI terminal session within the "redis" container...
elif [ "$1" == "redis" ] ; then
shift 1
if [ "$EXEC" == "yes" ]; then
ARGS+=(exec)
[ ! -t 0 ] && ARGS+=(-T)
ARGS+=(redis redis-cli)
else
ltw_is_not_running
fi
# Share the site...
elif [ "$1" == "share" ]; then
shift 1
if [ "$EXEC" == "yes" ]; then
docker run --init --rm -p "$LTW_SHARE_DASHBOARD":4040 -t beyondcodegmbh/expose-server:latest share http://host.docker.internal:"$APP_PORT" \
--server-host="$LTW_SHARE_SERVER_HOST" \
--server-port="$LTW_SHARE_SERVER_PORT" \
--auth="$LTW_SHARE_TOKEN" \
--subdomain="$LTW_SHARE_SUBDOMAIN" \
--domain="$LTW_SHARE_DOMAIN" \
"$@"
exit
else
ltw_is_not_running
fi
# Pass unknown commands to the "docker-compose" binary...
else
ARGS+=("$@")
fi
echo "Running: " "${DOCKER_COMPOSE[@]}" "${ARGS[@]}"
# Run Docker Compose with the defined arguments...
"${DOCKER_COMPOSE[@]}" "${ARGS[@]}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment