#!/usr/bin/env bash
#
# SPDX-FileCopyrightText: 2021 René de Hesselle <dehesselle@web.de>
#
# SPDX-License-Identifier: GPL-2.0-or-later

### description ################################################################

# This is a helper to create release archives and mount them.

### shellcheck #################################################################

# Nothing here.

### dependencies ###############################################################

#------------------------------------------------------ source jhb configuration

source "$(dirname "${BASH_SOURCE[0]}")"/../../etc/jhb.conf.sh

#------------------------------------------- source common functions from bash_d

# bash_d is already available (it's part of jhb configuration)

bash_d_include error

### variables ##################################################################

# Nothing here.

### functions ##################################################################

function create_tar
{
  local file=$ARTIFACT_DIR/$RELEASE_ARCHIVE

  echo_i "creating $file"

  tar -C "$WRK_DIR" -cp "$(basename "$VER_DIR")" |
    XZ_OPT=-T0 "$BIN_DIR"/xz > "$file"

  shasum -a 256 "$file" > "$file".sha256
  cat "$file".sha256
}

function create_dmg
{
  local file=$ARTIFACT_DIR/$RELEASE_ARCHIVE

  ( # create dmg
    local vol_name
    vol_name=$(basename "$VER_DIR")

    cd "$WRK_DIR" || exit 1
    hdiutil create -fs HFS+ -ov -format UDBZ \
      -srcfolder "$vol_name" \
      -volname "$vol_name" \
      "$file"
  )

  ( # create and print checksum
    cd "$(dirname "$file")" || exit 1
    shasum -a 256 "$(basename "$file")" > "$file".sha256
    cat "$file".sha256
  )
}

function mount_dmg
{
  local file=$REP_DIR/$RELEASE_ARCHIVE
  local mountpoint=$VER_DIR

  if [ ! -d "$mountpoint" ]; then
    mkdir -p "$mountpoint"
  fi

  echo_i "mounting $(basename "$file") may take some time"
  local device
  device=$(hdiutil attach -nomount "$file" | grep "^/dev/disk" |
    grep "Apple_HFS" | awk '{ print $1 }')
  echo_i "$file attached to $device"
  mount -o nobrowse,noowners,noquarantine,ro -t hfs "$device" "$mountpoint"
  echo_i "$device mounted to $mountpoint"
}

function unmount_dmg
{
  local mountpoint=$VER_DIR

  while : ; do   # unmount everything (in reverse order)
    local disk
    disk=$(mount | grep "$mountpoint" | tail -n1 | awk '{ print $1 }')
    disk=${disk%s[0-9]}  # cut off slice specification

    if [ ${#disk} -eq 0 ]; then
      break   # nothing to do here
    else
      # We loop over the 'eject' since it occasionally timeouts.
      while ! diskutil eject "$disk" > /dev/null; do
        echo_w "retrying to eject $disk in 5 seconds"
        sleep 5
      done

      echo_i "ejected $disk"
    fi
  done
}

function download_dmg
{
  if [ ! -d "$REP_DIR" ]; then
    mkdir -p "$REP_DIR"
  fi

  for url in "${RELEASE_URLS[@]}"; do
    local partial_download=$REP_DIR/${FUNCNAME[0]}  # TMP_DIR not available yet
    # download (at least) 100 kb of data
    curl -L "$url" 2>/dev/null | head -c 100000 > "$partial_download"
    # if we got 100 kb, it's not a "404 file not found"
    if [ "$(stat -f%z "$partial_download")" -eq 100000 ]; then
      echo_i "downloading $url"
      curl -o "$REP_DIR/$RELEASE_ARCHIVE" -L -C - "$url"
      break
    fi
  done

  rm "$partial_download"
}

function install_dmg
{
  local overlay_size=${1:-1}   # unit GiB, default 1

  local file=$REP_DIR/$RELEASE_ARCHIVE

  # download and mount read-only disk image
  if [ -f "$file" ]; then
    echo_i "using $file"
  else
    download_dmg
  fi
  mount_dmg

  # create writable overlay
  local device
  device=$(hdiutil attach -nomount ram://$((overlay_size * 1024 * 2048)) | xargs)
  newfs_hfs -v "$RELEASE_OVERLAY" "$device" >/dev/null
  echo_i "$overlay_size GiB ram attached to $device"
  mount -o nobrowse,rw,union -t hfs "$device" "$VER_DIR"
  echo_i "$device union-mounted at $VER_DIR"

  # Sadly, there are some limitations involved with union-mounting:
  #   - Files are not visible to macOS' versions of 'ls' or 'find'.
  #     (The GNU versions do work though.)
  #   - You cannot write in a location without having written to its
  #     parent location first. That's why we need to pre-create all directories
  #     below.
  #
  # (Shadow-mounting a dmg is not a feasible alternative due to its
  # bad write-performance.)

  # Create and run a script for mass-creating directories.
  echo_i "setting up directories in overlay"
  gfind "$VER_DIR" -mindepth 1 -type d \
    ! -path "$BLD_DIR/*" ! -path "$SRC_DIR/*" \
    -exec echo "mkdir {}" \; > "$VER_DIR"/create_dirs.sh
  chmod 755 "$VER_DIR"/create_dirs.sh
  "$VER_DIR"/create_dirs.sh
  rm "$VER_DIR"/create_dirs.sh
}

function uninstall_dmg
{
  unmount_dmg
}

function main
{
  local command=$1
  local option=$2

  case "$command" in
    create_dmg)
      create_dmg
      ;;
    create_tar)
      create_tar
      ;;
    install_dmg)
      install_dmg "$option"   # option: overlay size in GiB, defaul is 1
      ;;
    uninstall_dmg)
      uninstall_dmg
      ;;
    *)
      echo_e "usage: $0 {create_dmg|create_tar|install_dmg|uninstall_dmg}"
      ;;
  esac
}

### main #######################################################################

error_trace_enable

main "$@"
