#!/bin/bash

#
# File .......... swuk_repos_splice
# Author ........ Steve Haywood
# Website ....... http://www.spacewire.co.uk
# Project ....... Common (SpaceWire UK Tutorial)
# Date .......... 08 Feb 2025
# Version ....... 1.0
# Description ...
#   Splice together the 4 separate SWUK tutorial repositories into a collection
# of ordered directories that represent the change history of the projects as if
# they had originally been part of one single repository.
#

# Strict
set -euo pipefail

################################################################################
# Checkout a specific version of a repository into a shared area and copy the
# entire file structure into a separate directory.
# Arguments ...... $1 = Separate destination directory
#                  $2 = Hash of the required version from the repository
#                  $3 = Repository in which to checkout the files
#                  $4 = Destination directory for the repository checkout
# Return ......... None
# Shared (In) .... None
# Shared (Out) ... None
checkout_repo()
{
  # Declare local constants
  local -r history="history.tsv"  # Str: File containing the GIT history
  local -r dest=$1                # Str: Separate destination directory
  local -r hash=$2                # Str: Hash of the required version from the repository
  local -r repo=$3                # Str: Repository in which to checkout the files
  local -r proj=$4                # Str: Destination directory for the repository checkout

  # Remove checkout directory to avoid any staleness
  [ -d ${proj} ] && rm -rf ${proj}

  # Clone the repository
  git clone https://bitbucket.org/spacewire_firmware/${repo} ${proj}

  # Move into project subdirectory
  cd ${proj}

  # Get the commit comment, tag & tag comment
  local comment=$(git show ${hash} --no-patch --oneline --pretty="%s")
  local tag=$(git describe --tags --exact-match ${hash})
  local tcomment=""
  if [ -n "${tag}" ]; then
    tcomment=$(git tag -l --format='%(contents)' ${tag})
    tag="${proj}_${tag}"
  fi

  # Output the 3 fields into the history details file
  echo -e "${comment}\t${tag}\t${tcomment}" >> ../../${history}

  # Switch to a commit (version) using its hash
  git checkout ${hash}
  rm -rf .git

  # Move out of project subdirectory
  cd ..

  # Copy the entire directory structure
  cp -r . ../${dest}
}


################################################################################
# Splice together the four separate SWUK tutorial repositories in the correct
# order.
# Arguments ...... None
# Return ......... None
# Shared (In) .... None
# Shared (Out) ... None
splice_repos()
{
  # Declare local constants
  local -r repo="repo"  # Str: Repository directory

  # Create repository directory
  mkdir -p ${repo}

  # Move into repository directory
  cd ${repo}

  #              Dest   Hash      Repository               Project                  # Tutorial
  checkout_repo "0001" "630ee63" "common"                 "common"                  # 1
  checkout_repo "0002" "908af3b" "zedboard_hello_world"   "zedboard_hello_world"    # 2
  checkout_repo "0003" "ce7164b" "zedboard_leds_switches" "zedboard_leds_switches"  # 3
  checkout_repo "0004" "f1b445e" "zedboard_leds_switches" "zedboard_leds_buttons"   # 4
  checkout_repo "0005" "8827d6c" "zedboard_linux"         "zedboard_linux"          # 5
  checkout_repo "0006" "095dd72" "zedboard_linux"         "zedboard_linux"          # 6
  checkout_repo "0007" "26d544e" "zedboard_linux"         "zedboard_linux"          # 7
  checkout_repo "0008" "ad0542f" "zedboard_linux"         "zedboard_linux"          # 8a
  checkout_repo "0009" "bfc084e" "zedboard_linux"         "zedboard_linux"          # 8b
  checkout_repo "0010" "156d5b4" "zedboard_linux"         "zedboard_linux"          # 8c
  checkout_repo "0011" "785110e" "zedboard_linux"         "zedboard_linux"          # 10
  checkout_repo "0012" "c625e6b" "zedboard_linux"         "zedboard_linux"          # 11
  checkout_repo "0013" "89f9faf" "zedboard_linux"         "zedboard_linux"          # 12
  checkout_repo "0014" "acaaa4e" "zedboard_leds_switches" "zedboard_leds_switches"  # 13b
  checkout_repo "0015" "8d47468" "zedboard_linux"         "zedboard_linux"          # 13a
  checkout_repo "0016" "42e2ca1" "zedboard_leds_switches" "zedboard_leds_switches"  # 14b
  checkout_repo "0017" "5e865c5" "zedboard_linux"         "zedboard_linux"          # 14a
  checkout_repo "0018" "cc42e7b" "zedboard_leds_switches" "zedboard_leds_switches"  # 16a
  checkout_repo "0019" "5da451d" "common"                 "common"                  # 16b
  checkout_repo "0020" "980d0a8" "zedboard_linux"         "zedboard_linux"          # 16c
  checkout_repo "0021" "9bea7fd" "zedboard_linux"         "zedboard_linux"          # 16d
  checkout_repo "0022" "9841486" "zedboard_leds_switches" "zedboard_leds_switches"  # 17a
  checkout_repo "0023" "47363ef" "zedboard_linux"         "zedboard_linux"          # 17b
  checkout_repo "0024" "e5a2cde" "zedboard_linux"         "zedboard_linux"          # 18
  checkout_repo "0025" "fd3d8fb" "zedboard_linux"         "zedboard_linux"          # 19
  checkout_repo "0026" "ec080e8" "zedboard_linux"         "zedboard_linux"          # 20

  # Move out of repository directory
  cd ..

  # Delete repository directory
  rm -rf ${repo}
}


################################################################################
# Fix known issues within the checked out repositories.
# Arguments ...... None
# Return ......... None
# Shared (In) .... None
# Shared (Out) ... None
fix_repos()
{
  # Declare local variables
  local lineip  # Str: SED Search
  local lineop  # Str: SED Replace

  echo "Applying fixes for known repository issues!"

  # File put in too early, valid from 0003
  rm 0001/common/fw/src/script/zedboard_presets.tcl
  rm 0002/common/fw/src/script/zedboard_presets.tcl

  # File in wrong location & at this location it breaks the PetaLinux build
  mkdir -p 0024/zedboard_linux/os/petalinux/project-spec/meta-user/recipes-httpd/apache2
  mv 0024/zedboard_linux/os/petalinux/components/yocto/layers/meta-openembedded/meta-webserver/recipes-httpd/apache2/apache2_%.bbappend 0024/zedboard_linux/os/petalinux/project-spec/meta-user/recipes-httpd/apache2/apache2_%.bbappend
  rm -rf 0024/zedboard_linux/os/petalinux/components

  # Fix history for separated out LEDs & Buttons design
  lineip='Basic Zedboard design consisting of just the ZYNQ7 Processing System.\tzedboard_leds_switches_v1.0\tZYNQ & GPIO'
  lineop='Basic Zedboard design consisting of a ZYNQ7 Processing System controlling \& monitoring LEDs \& DIP Switches via a GPIO.\tzedboard_leds_switches_v1.0\tZYNQ \& GPIO'
  sed -i "s/${lineip}/${lineop}/" history.tsv

  lineip='Changed GPIO2 connection from DIP Switches (8-bit) to Push Buttons (5-bit).\tzedboard_leds_buttons_v2.0_int\tZYNQ, GPIO & Interrupts'
  lineop='Basic Zedboard design consisting of a ZYNQ7 Processing System controlling \& monitoring LEDs \& Push Buttons via a GPIO.\tzedboard_leds_buttons_v1.0\tZYNQ, GPIO \& Interrupts'
  sed -i "s/${lineip}/${lineop}/" history.tsv

  # Fix comment consistency
  lineip='Updated Firmware Identification fields to use static information from GIT\tzedboard_leds_switches_v4.0\tZYNQ, GPIO, Register Bank & Identification (timestamp & hash from GIT)'
  lineop='Updated Firmware Identification fields to use static information from GIT.\tzedboard_leds_switches_v4.0\tZYNQ, GPIO, Register Bank \& Identification (timestamp \& hash from GIT)'
  sed -i "s/${lineip}/${lineop}/" history.tsv
}


################################################################################
# Check if an argument option is set.
# Arguments ...... $1 ... Str: Option
# Return ......... Set (0=unset, 1=set)
# Shared (In) .... argv
# Shared (Out) ... None
option_set()
{
  [[ " ${argv[*]} " =~ " ${1} " ]] && echo 1 || echo 0
}


################################################################################
# Main function.
# Arguments ...... None
# Return ......... None
# Exit code ...... Status (0=success, 1=failure)
# Shared (In) .... argv
# Shared (Out) ... argv
main()
{
  # Declare local constants
  local -r  optfix="--fix"    # Str: Fix option name
  local -r  opthelp="--help"  # Str: Help option name
  local -Ar options=(         # ARR: Options & associated help information
    [${optfix}]="Fix known repository issues."
    [${opthelp}]="Display this help and exit."
  )
  local -ar optorder=(        # Arr: Help options display order
    ${optfix}
    ${opthelp}
  )

  # Declare local variables
  local    arg                # Str: Current argument from argv array
  local    project=""         # Str: Project directory [arg] (mandatory)
  local    option             # Str: Current option from optorder array

  # Display help information
  if (($(option_set ${opthelp}))); then
    echo "Usage: $(basename ${0}) PROJECT-DIRECTORY... [OPTION]..."
    echo "Splice the 4 SWUK project repositories into separate subdirectories in the PROJECT-DIRECTORY & generate a history report."
    echo
    for option in ${optorder[@]}
    do
      echo "      ${option} $(printf ' %.0s' {1..12} | head -c $((12-${#option}))) ${options[${option}]}"
    done
    echo
    exit 0
  fi

  # Get & check the arguments
  for arg in ${argv[@]}; do
    if [[ ${arg:0:2} == "--" ]]; then  # Option
      [[ ! -v options[${arg}] ]] && echo "Option (${arg}) is not recognised!" && exit 1
    elif [[ -z ${project} ]]; then  # Project directory
      project=${arg}
      [[ -d ${project} ]] && echo "Project directory (${arg}) already exists!" && exit 1
    else
      echo "Unexpected argument (${arg}) found!" && exit 1
      exit 1
    fi
  done

  # Further check the arguments
  [[ -z ${project} ]] && echo "No project directory specified!" && exit 1

  # Create project directory
  mkdir ${project}

  # Move into project directory
  cd ${project}

  # Do the repository splice
  splice_repos

  # Fix known repository issues
  (($(option_set ${optfix}))) &&
    fix_repos

  # Move out of project directory
  cd ..
}


################################################################################
# Opening gambit.
# Arguments ...... None
# Return ......... None
# Exit code ...... Status (0=success, 1=failure)
# Shared (In) .... $#, $@
# Shared (Out) ... argc, argv
declare -ri argc=${#}    # Int: Get argument count
declare -ra argv=(${@})  # Arr: Get argument values (space-separated) into array
main
exit 0
