Doc, tools for lokavaluto development
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

305 lines
7.6KB

  1. #!/bin/bash
  2. e() { printf "%s" "$*"; }
  3. warn() { e "${YELLOW}Warning:$NORMAL" "$*"$'\n' >&2 ; }
  4. info() { e "${BLUE}II$NORMAL" "$*"$'\n' >&2 ; }
  5. verb() { [ -z "$VERBOSE" ] || e "$*"$'\n' >&2; }
  6. debug() { [ -z "$DEBUG" ] || e "$*"$'\n' >&2; }
  7. err() { e "${RED}Error:$NORMAL $*"$'\n' >&2 ; }
  8. die() { err "$@" ; exit 1; }
  9. get_path() { (
  10. IFS=:
  11. for d in $PATH; do
  12. filename="$d/$1"
  13. [ -f "$filename" -a -x "$filename" ] && {
  14. echo "$d/$1"
  15. return 0
  16. }
  17. done
  18. return 1
  19. ) }
  20. ansi_color() {
  21. local choice="$1"
  22. if [ "$choice" == "tty" ]; then
  23. if [ -t 1 ]; then
  24. choice="yes"
  25. else
  26. choice="no"
  27. fi
  28. fi
  29. ANSI_ESC=$'\e['
  30. if [ "$choice" != "no" ]; then
  31. NORMAL="${ANSI_ESC}0m"
  32. GRAY="${ANSI_ESC}1;30m"
  33. RED="${ANSI_ESC}1;31m"
  34. GREEN="${ANSI_ESC}1;32m"
  35. YELLOW="${ANSI_ESC}1;33m"
  36. BLUE="${ANSI_ESC}1;34m"
  37. PINK="${ANSI_ESC}1;35m"
  38. CYAN="${ANSI_ESC}1;36m"
  39. WHITE="${ANSI_ESC}1;37m"
  40. DARKGRAY="${ANSI_ESC}0;30m"
  41. DARKRED="${ANSI_ESC}0;31m"
  42. DARKGREEN="${ANSI_ESC}0;32m"
  43. DARKYELLOW="${ANSI_ESC}0;33m"
  44. DARKBLUE="${ANSI_ESC}0;34m"
  45. DARKPINK="${ANSI_ESC}0;35m"
  46. DARKCYAN="${ANSI_ESC}0;36m"
  47. DARKWHITE="${ANSI_ESC}0;37m"
  48. fi
  49. ansi_color="$choice"
  50. export NORMAL \
  51. GRAY RED GREEN YELLOW BLUE PINK CYAN WHITE DARKGRAY \
  52. DARKRED DARKGREEN DARKYELLOW DARKBLUE DARKPINK DARKCYAN \
  53. ansi_color
  54. }
  55. depends() {
  56. ## Avoid colliding with variables that are created with depends.
  57. local __i __path __new_name
  58. for __i in "$@"; do
  59. if ! __path=$(get_path "$__i"); then
  60. __new_name="$(echo "${__i//-/_}")"
  61. if [ "$__new_name" != "$__i" ]; then
  62. depends "$__new_name"
  63. else
  64. err "dependency check: couldn't find '$__i' required command."
  65. exit 1
  66. fi
  67. else
  68. if ! test -z "$__path" ; then
  69. export "$(echo "${__i//- /__}")"="$__path"
  70. fi
  71. fi
  72. done
  73. }
  74. get_os() {
  75. local uname_output
  76. uname_output="$(uname -s)"
  77. case "${uname_output}" in
  78. Linux*)
  79. if [[ "$(< /proc/version)" =~ ^.*@(Microsoft|WSL).*$ ]]; then
  80. e wsl
  81. elif [[ "$(< /proc/version)" =~ ^.*-microsoft-.*$ ]]; then
  82. e wsl2
  83. elif [[ "$(< /proc/version)" == *-boot2docker* ]] && [[ -d /Users ]]; then
  84. e docker-toolbox-for-mac
  85. else
  86. e linux
  87. fi
  88. ;;
  89. Darwin*) e mac;;
  90. CYGWIN*) e cygwin;;
  91. MINGW*) e mingw;;
  92. *) e "UNKNOWN:${uname_output}";;
  93. esac
  94. }
  95. OS=$(get_os) || {
  96. err "Couldn't figure what OS you are running."
  97. exit 1
  98. }
  99. fn.exists() { declare -F "$1" >/dev/null; }
  100. ## copy stdin to file, archive previous existing file if any
  101. install_file() {
  102. local path="$1" tmpfile
  103. tmpfile="$(mktemp)"
  104. cat > "${tmpfile}" || return 1
  105. mkdir -vp "${path%/*}" || exit 1
  106. if [[ -e "$path" ]]; then
  107. if ! diff "${tmpfile}" "${path}" >/dev/null 2>&1;then
  108. info "File '$path' exists but is different, archiving current content and replacing it."
  109. candidate="${path}.bak"
  110. n=1
  111. while [ -e "$candidate" ]; do
  112. candidate="${path}.bak.$((n++))"
  113. done
  114. echo "Archiving previous version of '$path'"
  115. mv -v "${path}" "$candidate" || return 1
  116. else
  117. info "File '$path' exists and is already with the right content."
  118. rm -f "$tmpfile"
  119. return
  120. fi
  121. fi
  122. echo "Creating '${path}'."
  123. mv "${tmpfile}" "$path" || return 1
  124. }
  125. get_charm_store() {
  126. local branch="${1:master}"
  127. if ! [ -d "$CHARM_PATH" ]; then
  128. info "Creating charm-store in '$CHARM_PATH'.."
  129. git clone https://git.0k.io/0k-charms.git -b "$branch" "$CHARM_PATH" || {
  130. echo " .. ${RED}Failed${NORMAL}." >&2
  131. return 1
  132. }
  133. echo " .. ${GREEN}Done${NORMAL}." >&2
  134. else
  135. info "Updating existing charm-store in '$CHARM_PATH'."
  136. cd "$CHARM_PATH" || exit 1
  137. git fetch &&
  138. git checkout "$branch" &&
  139. git pull -r || {
  140. warn "Could not update charm-store, do you have devs ingoing ?"
  141. echo " .. ${BLUE}No action${NORMAL}." >&2
  142. return 0
  143. }
  144. echo " .. ${GREEN}Done${NORMAL}." >&2
  145. fi
  146. }
  147. fetch_binary() {
  148. local url="$1" name="$2" bin_path tmpfile
  149. mkdir -p "$BIN_PATH" || return 1
  150. info "Downloading '$name'..."
  151. (
  152. tmpfile=$(mktemp) && trap "rm -f '$tmpfile'" EXIT &&
  153. curl -sS "$url" > "$tmpfile" &&
  154. chmod +x "$tmpfile" || {
  155. echo " .. ${RED}Failed${NORMAL}." >&2
  156. return 1
  157. }
  158. if [[ "$(cat "$tmpfile")" == "<!DOCTYPE html>"* ]]; then
  159. echo " $GRAY|$NORMAL fetching: $url" >&2
  160. echo " .. ${RED}Failed${NORMAL} (fetched content is HTML !?!)." >&2
  161. return 1
  162. fi
  163. if [ -e "$BIN_PATH/$name" ] && diff "$tmpfile" "$BIN_PATH/$name" >/dev/null 2>&1; then
  164. echo " .. ${GREEN}Done${NORMAL} (File '$BIN_PATH/$name' was already up to date.)" >&2
  165. else
  166. mv "$tmpfile" "$BIN_PATH/$name" &&
  167. echo " .. ${GREEN}Done${NORMAL}." >&2
  168. fi
  169. ) || return 1
  170. hash -r
  171. if bin_path=$(type -p "$name"); then
  172. if [ "$bin_path" != "$BIN_PATH/$name" ]; then
  173. warn "Found a '$name' in \$PATH at '$bin_path'." \
  174. $'\n'" That doesn't match expected location '$BIN_PATH/$name'." \
  175. $'\n'" You might need to change you \$PATH to include '$BIN_PATH' before '${bin_path%/*}'."
  176. fi
  177. fi
  178. }
  179. get_docker_ip() {
  180. fetch_binary https://git.0k.io/0k-docker.git/plain/src/bin/docker-ip docker-ip
  181. }
  182. install.linux() {
  183. depends docker curl git
  184. if [ "$UID" != 0 ]; then
  185. BIN_PATH=~/bin
  186. CHARM_PATH=~/.charm-store
  187. DEFAULT_COMPOSE_YML=~/.compose/etc/compose.yml
  188. COMPOSE_OPTION_FILE=~/.compose/etc/local.conf
  189. else
  190. BIN_PATH=/usr/local/bin
  191. CHARM_PATH=/srv/charm-store
  192. DEFAULT_COMPOSE_YML=/etc/compose/compose.yml
  193. COMPOSE_OPTION_FILE=/etc/compose/local.conf
  194. fi
  195. fetch_binary "https://git.0k.io/0k-compose.git/plain/bin/compose?h=${DEPLOY_REF}" compose || return 1
  196. get_docker_ip || return 1
  197. if [[ ":$PATH:" != *":$BIN_PATH:"* ]]; then
  198. warn "Please ensure that '$BIN_PATH' is in your \$PATH to ensure" \
  199. "the simple usage of 'compose' command."
  200. fi
  201. get_charm_store "${DEPLOY_REF}" || return 1
  202. cat <<EOF | install_file "$COMPOSE_OPTION_FILE" || return 1
  203. #CHARM_STORE=$CHARM_PATH
  204. COMPOSE_DOCKER_IMAGE=docker.0k.io/compose:${DEPLOY_REF//\//-}
  205. if [ "\${docker_run_opts+x}" ]; then
  206. docker_run_opts+=(
  207. "-e" "DEFAULT_PROJECT_NAME=lokavaluto"
  208. )
  209. fi
  210. #DEFAULT_COMPOSE_YML=$DEFAULT_COMPOSE_YML
  211. EOF
  212. }
  213. install.docker-toolbox-for-mac() {
  214. install.linux
  215. }
  216. install.mingw() {
  217. ## will install compose, but can't be used
  218. install.linux
  219. }
  220. install.wsl() {
  221. BIN_PATH=~/bin
  222. CHARM_PATH=~/.charm-store
  223. get_charm_store "${DEPLOY_REF}" || return 1
  224. get_docker_ip
  225. }
  226. install.wsl2() {
  227. install.linux
  228. }
  229. install.mac() {
  230. install.linux
  231. }
  232. run() {
  233. OS="$(get_os)"
  234. info "Detected system is '$OS'"
  235. if fn.exists "install.$OS"; then
  236. "install.$OS"
  237. else
  238. echo "System '$OS' not supported yet." >&2
  239. fi
  240. }
  241. ##
  242. ## Code
  243. ##
  244. ansi_color tty
  245. DEPLOY_REF="${DEPLOY_REF:-lokavaluto/dev/master}"
  246. run