app.sh 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. #!/usr/bin/env bash
  2. set -euo pipefail
  3. # use greadlink instead of readlink on osx
  4. if [[ "$(uname)" == "Darwin" ]]; then
  5. rdlk=greadlink
  6. else
  7. rdlk=readlink
  8. fi
  9. ROOT_FOLDER="$($rdlk -f $(dirname "${BASH_SOURCE[0]}")/..)"
  10. STATE_FOLDER="${ROOT_FOLDER}/state"
  11. show_help() {
  12. cat << EOF
  13. app 0.0.1
  14. CLI for managing Tipi apps
  15. Usage: app <command> <app> [<arguments>]
  16. Commands:
  17. install Pulls down images for an app and starts it
  18. uninstall Removes images and destroys all data for an app
  19. stop Stops an installed app
  20. start Starts an installed app
  21. compose Passes all arguments to docker-compose
  22. ls-installed Lists installed apps
  23. EOF
  24. }
  25. # Get field from json file
  26. function get_json_field() {
  27. local json_file="$1"
  28. local field="$2"
  29. echo $(jq -r ".${field}" "${json_file}")
  30. }
  31. list_installed_apps() {
  32. str=$(get_json_field ${STATE_FOLDER}/apps.json installed)
  33. echo $str
  34. }
  35. if [ -z ${1+x} ]; then
  36. command=""
  37. else
  38. command="$1"
  39. fi
  40. # Lists installed apps
  41. if [[ "$command" = "ls-installed" ]]; then
  42. list_installed_apps
  43. exit
  44. fi
  45. if [ -z ${2+x} ]; then
  46. show_help
  47. exit 1
  48. else
  49. app="$2"
  50. root_folder_host="$3"
  51. app_dir="${ROOT_FOLDER}/apps/${app}"
  52. app_data_dir="${ROOT_FOLDER}/app-data/${app}"
  53. if [[ -z "${app}" ]] || [[ ! -d "${app_dir}" ]]; then
  54. echo "Error: \"${app}\" is not a valid app"
  55. exit 1
  56. fi
  57. if [[ -z "${root_folder_host}" ]]; then
  58. echo "Error: Root folder not provided"
  59. exit 1
  60. fi
  61. fi
  62. if [ -z ${3+x} ]; then
  63. args=""
  64. else
  65. args="${@:3}"
  66. fi
  67. compose() {
  68. local app="${1}"
  69. shift
  70. local architecture="$(uname -m)"
  71. if [[ "$architecture" == "aarch64" ]]; then
  72. architecture="arm64"
  73. fi
  74. # App data folder
  75. local env_file="${ROOT_FOLDER}/.env"
  76. local app_compose_file="${app_dir}/docker-compose.yml"
  77. # Pick arm architecture if running on arm and if the app has a docker-compose.arm.yml file
  78. if [[ "$architecture" == "arm"* ]] && [[ -f "${app_dir}/docker-compose.arm.yml" ]]; then
  79. app_compose_file="${app_dir}/docker-compose.arm.yml"
  80. fi
  81. local common_compose_file="${ROOT_FOLDER}/apps/docker-compose.common.yml"
  82. local app_dir="${ROOT_FOLDER}/apps/${app}"
  83. # Vars to use in compose file
  84. export APP_DATA_DIR="${root_folder_host}/app-data/${app}"
  85. export APP_DIR="${app_dir}"
  86. export ROOT_FOLDER_HOST="${root_folder_host}"
  87. export ROOT_FOLDER="${ROOT_FOLDER}"
  88. # Docker-compose does not support multiple env files
  89. # --env-file "${env_file}" \
  90. docker-compose \
  91. --env-file "${ROOT_FOLDER}/app-data/${app}/app.env" \
  92. --project-name "${app}" \
  93. --file "${app_compose_file}" \
  94. --file "${common_compose_file}" \
  95. "${@}"
  96. }
  97. # Install new app
  98. if [[ "$command" = "install" ]]; then
  99. compose "${app}" pull
  100. # Copy default data dir to app data dir if it exists
  101. if [[ -d "${ROOT_FOLDER}/apps/${app}/data" ]]; then
  102. cp -r "${ROOT_FOLDER}/apps/${app}/data" "${app_data_dir}/data"
  103. fi
  104. # Remove all .gitkeep files from app data dir
  105. find "${app_data_dir}" -name ".gitkeep" -exec rm -f {} \;
  106. chown -R "1000:1000" "${app_data_dir}"
  107. compose "${app}" up -d
  108. exit
  109. fi
  110. # Removes images and destroys all data for an app
  111. if [[ "$command" = "uninstall" ]]; then
  112. echo "Removing images for app ${app}..."
  113. # compose "${app}" down --remove-orphans
  114. echo "Deleting app data for app ${app}..."
  115. if [[ -d "${app_data_dir}" ]]; then
  116. rm -rf "${app_data_dir}"
  117. fi
  118. echo "Successfully uninstalled app ${app}"
  119. exit
  120. fi
  121. # Stops an installed app
  122. if [[ "$command" = "stop" ]]; then
  123. echo "Stopping app ${app}..."
  124. compose "${app}" down --remove-orphans --rmi all
  125. compose "${app}" rm --force --stop
  126. exit
  127. fi
  128. # Starts an installed app
  129. if [[ "$command" = "start" ]]; then
  130. echo "Starting app ${app}..."
  131. compose "${app}" pull
  132. compose "${app}" up --detach
  133. exit
  134. fi
  135. # Passes all arguments to docker-compose
  136. if [[ "$command" = "compose" ]]; then
  137. compose "${app}" ${args}
  138. exit
  139. fi
  140. # If we get here it means no valid command was supplied
  141. # Show help and exit
  142. show_help
  143. exit 1