|
| 1 | +#!/usr/bin/env bash |
| 2 | + |
| 3 | +set -o errexit # Exit script when a command exits with non-zero status. |
| 4 | +set -o errtrace # Exit on error inside any functions or sub-shells. |
| 5 | +set -o nounset # Exit script on use of an undefined variable. |
| 6 | +set -o pipefail # Return exit status of the last command in the pipe that exited with a non-zero exit code |
| 7 | + |
| 8 | +: "${DOCKER:=docker}" |
| 9 | + |
| 10 | +# ============================================================================== |
| 11 | +# Exit codes |
| 12 | +# ------------------------------------------------------------------------------ |
| 13 | +: readonly -i "${EXIT_OK:=0}" |
| 14 | +: readonly -i "${EXIT_NOT_ENOUGH_PARAMETERS:=65}" |
| 15 | +: readonly -i "${EXIT_INVALID_PARAMETER:=66}" |
| 16 | +: readonly -i "${EXIT_COULD_NOT_FIND_DIRECTORY:=75}" |
| 17 | +: readonly -i "${EXIT_NOT_CORRECT_TYPE:=81}" |
| 18 | + |
| 19 | +# ------------------------------------------------------------------------------ |
| 20 | +# Foreground colors |
| 21 | +# ------------------------------------------------------------------------------ |
| 22 | +: readonly "${COLOR_BLUE:=$(tput setaf 4)}" |
| 23 | +: readonly "${COLOR_GREEN:=$(tput setaf 2)}" |
| 24 | +: readonly "${COLOR_RED:=$(tput setaf 1)}" |
| 25 | +: readonly "${COLOR_WHITE:=$(tput setaf 7)}" |
| 26 | +# ------------------------------------------------------------------------------ |
| 27 | +: readonly "${RESET_TEXT:=$(tput sgr0)}" # turn off all attributes |
| 28 | +# ============================================================================== |
| 29 | + |
| 30 | + |
| 31 | +# ============================================================================== |
| 32 | +## Run the SimplyCode Docker container |
| 33 | +# ------------------------------------------------------------------------------ |
| 34 | +## \nUsage: $0 [-dh][-i <docker-image>] <project-path> |
| 35 | +## |
| 36 | +## Where: |
| 37 | +## <docker-image> is an alternative Docker image to use |
| 38 | +## <project-path> is the path to the SimplyCode project to run |
| 39 | +## |
| 40 | +## Options: |
| 41 | +## -d|--dry-run Show the command that would be run without executing it |
| 42 | +## -h|--help Print this help dialogue and exit |
| 43 | +## -i|--docker-image=<docker-image> Use the specified Docker image |
| 44 | +## |
| 45 | +## Any additional arguments will be passed to the `docker run` command. |
| 46 | +## |
| 47 | +## For example: |
| 48 | +## |
| 49 | +## $0 <project-path> /bin/bash |
| 50 | +## |
| 51 | +## The Docker executable can be overridden by setting the DOCKER environmental |
| 52 | +## variable before calling this script: |
| 53 | +## |
| 54 | +## DOCKER=/usr/local/docker $0 <project-path> |
| 55 | +## |
| 56 | +## The SimplyCode Docker container will be run with the given project path mounted |
| 57 | +## to the container's /var/www/www/api/data directory. If the project has an assets |
| 58 | +## directory, this will be mounted to /var/www/html/assets. |
| 59 | +# ============================================================================== |
| 60 | +usage() { |
| 61 | + local sScript sUsage |
| 62 | + |
| 63 | + sScript="$(basename "$0")" |
| 64 | + sUsage="$(grep '^##' < "$0" | cut -c4-)" |
| 65 | + |
| 66 | + echo -e "${sUsage//\$0/${sScript}}" |
| 67 | +} |
| 68 | + |
| 69 | +error(){ |
| 70 | + message "ERROR" "${COLOR_RED}" "${@}" >&2 |
| 71 | +} |
| 72 | + |
| 73 | +info(){ |
| 74 | + message "INFO" "${COLOR_BLUE}" "${@}" |
| 75 | +} |
| 76 | + |
| 77 | +message(){ |
| 78 | + local sType="${1?Three parameters required: <type> <color> <message>}" |
| 79 | + local sColor="${2?Three parameters required: <type> <color> <message>}" |
| 80 | + local sMessage="${3?Three parameters required: <type> <color> <message>}" |
| 81 | + |
| 82 | + echo -e "${COLOR_WHITE}[${sColor}${sType}${COLOR_WHITE}]${RESET_TEXT} ${sMessage}" |
| 83 | + |
| 84 | + # Each additional parameter will be treated as extra information to display with the error |
| 85 | + if [[ "$#" -gt 3 ]]; then |
| 86 | + shift 3 |
| 87 | + for sMessage in "$@"; do |
| 88 | + echo -e " ${sMessage}" |
| 89 | + done |
| 90 | + fi |
| 91 | +} |
| 92 | + |
| 93 | +run_simplycode_docker() { |
| 94 | + dryRun() { |
| 95 | + local sResult |
| 96 | + |
| 97 | + DOCKER='echo' |
| 98 | + sResult=$(executeCommand "${@}") |
| 99 | + |
| 100 | + iLines=$(echo "${sResult}" | sed -E 's/ --/\n--/g' | wc -l) |
| 101 | + sResult="$(echo -n "${sResult}" | sed -E 's/ --/ \\\n --/g' | sed -n "1,${iLines}p")" |
| 102 | + |
| 103 | + echo -en "docker " |
| 104 | + echo -n "${sResult}" | head -n -1 |
| 105 | + echo -n "${sResult}" | tail -n 1 | cut -d ' ' -f 5-6 | sed -E 's/$/ \\/g' | sed 's/^/ /' |
| 106 | + echo -n "${sResult}" | tail -n 1 | cut -d ' ' -f 7- | sed -E 's/ / \\\n/g' | sed 's/^/ /' |
| 107 | + } |
| 108 | + |
| 109 | + executeCommand() { |
| 110 | + local sDockerImage sProjectPath |
| 111 | + |
| 112 | + readonly sDockerImage="${1?Two parameters required: <docker-image> <project-path>}" |
| 113 | + shift |
| 114 | + readonly sProjectPath="${1?Two parameters required: <docker-image> <project-path>}" |
| 115 | + shift |
| 116 | + |
| 117 | + # ====================================================================== |
| 118 | + # Build the run command |
| 119 | + # ---------------------------------------------------------------------- |
| 120 | + local -a aCommand=("${DOCKER}" 'run') |
| 121 | + |
| 122 | + aCommand+=( |
| 123 | + '--env' "USER_GID=$(id -g)" |
| 124 | + '--env' "USER_ID=$(id -u)" |
| 125 | + '--interactive' |
| 126 | + '--network=default' |
| 127 | + '--publish' '80:80' |
| 128 | + '--publish' '443:443' |
| 129 | + '--rm' |
| 130 | + '--tty' |
| 131 | + '--volume' "${sProjectPath}:/var/www/www/api/data" |
| 132 | + ) |
| 133 | + |
| 134 | + if [[ -d "${sProjectPath}/assets" ]]; then |
| 135 | + aCommand+=( |
| 136 | + '--volume' "${sProjectPath}/assets:/var/www/html/assets" |
| 137 | + ) |
| 138 | + fi |
| 139 | + |
| 140 | + aCommand+=( |
| 141 | + "${sDockerImage}" |
| 142 | + "${@}" |
| 143 | + ) |
| 144 | + |
| 145 | + # @TODO: Split command creation and execution into separate functions |
| 146 | + # so dry-run can be simplified |
| 147 | + |
| 148 | + "${aCommand[@]}" |
| 149 | + } |
| 150 | + |
| 151 | + local -a aParameters |
| 152 | + local sArgument sDockerImage |
| 153 | + local bDryRun=false |
| 154 | + |
| 155 | + aParameters=() |
| 156 | + |
| 157 | + sDockerImage='ghcr.io/simplyedit/simplycode-docker:main' |
| 158 | + |
| 159 | + while (( "$#" )); do |
| 160 | + sArgument="${1}" |
| 161 | + shift |
| 162 | + case "${sArgument}" in |
| 163 | + -d | --dry-run) |
| 164 | + bDryRun=true |
| 165 | + ;; |
| 166 | + |
| 167 | + -\? | -h | --help) |
| 168 | + usage |
| 169 | + exit "${EXIT_OK}" |
| 170 | + ;; |
| 171 | + |
| 172 | + -i | --docker-image | --docker-image=?*) |
| 173 | + # If the parameter contains a `=` the path is part of the param, so we need to split it to get the value |
| 174 | + if grep '=' <(echo "${sArgument}");then |
| 175 | + sDockerImage="${sArgument#*=}" |
| 176 | + else |
| 177 | + # Else, the next param is the value, unless no param is provided |
| 178 | + if [[ -n "${1:-}" && ! "${1}" =~ ^- ]]; then |
| 179 | + sDockerImage="${1}" |
| 180 | + shift |
| 181 | + else |
| 182 | + error "No value provided for ${sDockerImage}" "Call with --help for more information." |
| 183 | + exit "${EXIT_NOT_ENOUGH_PARAMETERS}" |
| 184 | + fi |
| 185 | + fi |
| 186 | + ;; |
| 187 | + |
| 188 | + --*|-*) |
| 189 | + error "Invalid option '${sArgument}'" "Call with --help for more information." |
| 190 | + exit "${EXIT_INVALID_PARAMETER}" |
| 191 | + ;; |
| 192 | + |
| 193 | + *) |
| 194 | + aParameters+=("${sArgument}") |
| 195 | + ;; |
| 196 | + esac |
| 197 | + done |
| 198 | + |
| 199 | + if [[ "${#aParameters[@]}" -lt 1 ]]; then |
| 200 | + error "One parameter required: <project-path>" "Call with --help for more information." |
| 201 | + exit "${EXIT_NOT_ENOUGH_PARAMETERS}" |
| 202 | + fi |
| 203 | + |
| 204 | + local sProjectPath="${aParameters[0]}" |
| 205 | + sProjectPath="$(realpath "${sProjectPath}")" |
| 206 | + aParameters=( "${aParameters[@]:1}" ) |
| 207 | + |
| 208 | + if [[ ! -e "${sProjectPath}" ]];then |
| 209 | + error "Could not find directory: ${sProjectPath}" |
| 210 | + exit "${EXIT_COULD_NOT_FIND_DIRECTORY}" |
| 211 | + elif [[ ! -d "${sProjectPath}" ]];then |
| 212 | + error "Provided path is not a directory: ${sProjectPath}" |
| 213 | + exit "${EXIT_NOT_CORRECT_TYPE}" |
| 214 | + fi |
| 215 | + |
| 216 | + if [[ "${bDryRun}" == true ]]; then |
| 217 | + info "Dry run enabled. The following command would be run:\n" |
| 218 | + dryRun "${sDockerImage}" "${sProjectPath}" "${aParameters[@]}" |
| 219 | + echo "" |
| 220 | + else |
| 221 | + executeCommand "${sDockerImage}" "${sProjectPath}" "${aParameters[@]}" |
| 222 | + fi |
| 223 | +} |
| 224 | + |
| 225 | +if [[ ${BASH_SOURCE[0]} != "$0" ]]; then |
| 226 | + export -f run_simplycode_docker |
| 227 | +else |
| 228 | + run_simplycode_docker "${@}" |
| 229 | +fi |
| 230 | + |
| 231 | +#EOF |
0 commit comments