#!/usr/bin/env bash
#===============================================================================
#
#             FILE: docker.sh
#            USAGE: bash docker.sh
#
#      DESCRIPTION: installs docker (via get.docker.com), a minimal daemon.json,
#                   docker bash-completion, docker-compose and ctop
#                   on compatible linux hosts (amd64).
#
#     REQUIREMENTS: curl, wget, systemd, bash, apt
#
#       OS SUPPORT: Linux
#   DISTRO SUPPORT: Debian-like
#             ARCH: amd64
#
#           AUTHOR: Guto Carvalho, guto@bolha.io
#             SITE: https://gutocarvalho.net
#         MASTODON: @gutocarvalho@bolha.us
#         PIXELFED: @gutocarvalho@bolha.photos
#      WRITEFREELY: @gutocarvalho@bolha.blog
#       MATTERMOST: @gutocarvalho:mattermost.bolha.chat
#
#     ORGANIZATION: gutocarvalho.net, gcn.sh, bolha.io
#
#          CREATED: 2024-09-14
#          UPDATED: 2026-08-13
#             REPO: https://gitlab.gutocarvalho.net/open/install
#
#     CONTRIBUTORS: name, email, mastodon
#
#     The code is simple on purpose: we want it to be friendly for people
#     that are starting with shell language and programming logic.
#
#     This script was designed to run on a clean, brand new machine/vm/vps.
#
#===============================================================================

set -o nounset                              # treat unset variables as an error

## 1. CONSTANTS/VARIABLES ######################################################

COMPOSE_ARCH="linux-x86_64"  # amd64 build of docker-compose
CTOP_ARCH="linux-amd64"      # amd64 build of ctop

## 2. HELPERS #################################################################

### abort: print an error message and stop the script
function abort() {
  echo -e "\nError: $1" >&2
  echo -e "Tip: run 'bash -x docker.sh' to see exactly what failed.\n" >&2
  exit 1
}

### check_root: this script must run as root
function check_root() {
  if [ "$(id -u)" != "0" ]; then
    abort "this script needs to run as root. Become root with 'su -' or 'sudo -i', then try again."
  fi
}

### need_cmd: make sure a required command exists
function need_cmd() {
  if ! command -v "$1" >/dev/null 2>&1; then
    abort "'$1' is required but was not found. Please install it first."
  fi
}

### refuse_if_present: stop if the tool we are about to install already exists
function refuse_if_present() {
  if command -v "$1" >/dev/null 2>&1; then
    abort "'$1' is already installed at $(command -v "$1"). Remove it first, then run this script again."
  fi
}

## 3. INSTALL FUNCTIONS #######################################################

### 3.1 install docker
function install_docker() {
  echo -e "\n>>> Installing docker...\n"
  curl -fsSL https://get.docker.com | bash
  command -v docker >/dev/null 2>&1 || abort "docker installation failed."
  systemctl enable --now docker
  echo "docker installed: $(docker --version)"
}

### 3.2 install docker bash-completion for the root user
function install_docker_completion() {
  echo -e "\n>>> Installing docker bash-completion for root...\n"
  apt install -y bash-completion || abort "could not install bash-completion."
  docker completion bash > /etc/bash_completion.d/docker
  if ! grep -q '/etc/bash_completion' /root/.bashrc 2>/dev/null; then
    echo "if [ -f /etc/bash_completion ]; then . /etc/bash_completion; fi" >> /root/.bashrc
  fi
  echo "docker bash-completion installed."
}

### 3.3 install a minimal daemon.json for dockerd
function install_docker_config() {
  echo -e "\n>>> Installing a minimal /etc/docker/daemon.json...\n"
  wget -qO /etc/docker/daemon.json https://install.gutocarvalho.net/daemon.json \
    || abort "could not download daemon.json."
  systemctl restart docker || abort "docker failed to restart with the new daemon.json."
  echo "daemon.json installed."
}

### 3.4 install docker-compose (standalone binary)
function install_compose() {
  echo -e "\n>>> Installing docker-compose...\n"
  cd /tmp || abort "could not enter /tmp."
  curl -s https://api.github.com/repos/docker/compose/releases/latest \
    | grep browser_download_url | grep -v sha256 | grep "$COMPOSE_ARCH" \
    | cut -d '"' -f 4 | wget -qi -
  mv "docker-compose-$COMPOSE_ARCH" /usr/local/bin/docker-compose \
    || abort "docker-compose download failed."
  chmod +x /usr/local/bin/docker-compose
  echo "docker-compose installed: $(docker-compose --version)"
}

### 3.5 install ctop
function install_ctop() {
  echo -e "\n>>> Installing ctop...\n"
  cd /tmp || abort "could not enter /tmp."
  local ctop_version
  ctop_version=$(curl -s https://api.github.com/repos/bcicen/ctop/releases/latest \
    | grep browser_download_url | grep "$CTOP_ARCH" | cut -d '"' -f 4 \
    | awk -F'/download/' '{print $2}' | awk -F'/' '{print $1}' | sed 's/v//')
  curl -s https://api.github.com/repos/bcicen/ctop/releases/latest \
    | grep browser_download_url | grep "$CTOP_ARCH" | cut -d '"' -f 4 | wget -qi -
  mv "ctop-${ctop_version}-${CTOP_ARCH}" /usr/local/bin/ctop \
    || abort "ctop download failed."
  chmod +x /usr/local/bin/ctop
  echo "ctop installed: $(ctop -v)"
}

### 3.6 install the humaniza log filter
# a tiny stdin filter that humanizes timestamps and colorizes log levels,
# e.g.  docker logs -f --tail=10 <container> | humaniza
function install_humaniza() {
  echo -e "\n>>> Installing the humaniza log filter...\n"
  wget -qO /usr/local/bin/humaniza https://install.gutocarvalho.net/humaniza \
    || abort "could not download humaniza."
  chmod +x /usr/local/bin/humaniza
  echo "humaniza installed."
}

## 4. EXECUTING ###############################################################

check_root
need_cmd curl
need_cmd wget

refuse_if_present docker
refuse_if_present docker-compose
refuse_if_present ctop

install_docker
install_docker_completion
install_docker_config
install_compose
install_ctop
install_humaniza

## 5. NOTIFICATIONS ###########################################################

echo -e "\n----------------------------------------------------------------------------------"
echo -e "\nAll done! You now have:"
echo "  - docker:         $(which docker), $(docker --version)"
echo "  - docker-compose: $(which docker-compose), $(docker-compose --version)"
echo "  - ctop:           $(which ctop), $(ctop -v)"
echo "  - humaniza:       $(which humaniza) (docker logs -f --tail=10 <c> | humaniza)"
echo -e "\nEnjoy it!"
echo -e "\nWant to know more about our collective? Visit https://bolha.io and consider joining us! ;)"
echo -e "Come and visit our mastodon instance:    https://bolha.us"
echo -e "Come and visit our mattermost instance:  https://mattermost.bolha.chat"
echo -e "Say hello on the fediverse:              @gutocarvalho@bolha.us"
echo -e "\n----------------------------------------------------------------------------------\n"
