#!/usr/bin/env bash
# * bake
# ** Usage

set -e

################################################################################
usage() {
    cat <<EOF
bake - light-medium project scripting (new). See also: make, ./Shake.hs

Commands:
./bake              - show this help
./bake relfiles     - symlink important files temporarily in .relfiles/
./bake prep VERSION - prepare this release on today's date
./bake bin          - push the current branch to CI to generate binaries
./bake lastweek     - show last week info useful for TWIH

prep does the following:
- autocreates and switches to the appropriate release branch
- updates all hledger package versions
- updates all built-in docs
- updates all changelogs
VERSION is major (1.25), minor (1.25.1), fixup (1.25.1.1) or preview (1.25.99.1)
(see RELEASING.md).

Setting PAUSE=1, ECHO=1, and/or DRY=1 will cause commands to 
be run one at a time, logged, or logged without running.
EOF
    exit
}

# ** hledger version numbers

# First 0-2 parts of a dotted version number.
versionMajorPart() {
  echo "$1" | sed -E 's/([[:digit:]]+(\.[[:digit:]]+)?).*/\1/'  # seriously...
}

# Third part of a dotted version number, if any.
versionMinorPart() {
  echo "$1" | sed -E -e 's/^[[:digit:]]+(\.[[:digit:]]+(\.)?)?//' -e 's/^([[:digit:]]+).*/\1/'
}

# Fourth part of a dotted version number, if any.
versionFourthPart() {
  echo "$1" | sed -E -e 's/^[[:digit:]]+(\.[[:digit:]]+(\.[[:digit:]]+(\.)?))//' -e 's/^([[:digit:]]+).*/\1/'
}

# Does this dotted version number have a .99 third part and no fourth part ?
versionIsDev() {
  V="$1"
  test "$(versionMinorPart "$V")" = 99 -a -z "$(versionFourthPart "$V")"
}

# Does this dotted version number have a .99 third part and a fourth part ?
versionIsPreview() {
  V="$1"
  test "$(versionMinorPart "$V")" = 99 -a -n "$(versionFourthPart "$V")"
}

# Increment a major version number to the next.
majorVersionIncrement() {
  python3 -c "print($1 + 0.01)"
}

# Appropriate release branch name for the given version number.
versionReleaseBranch() {
  V="$1"
  MAJOR=$(versionMajorPart "$V")
  if versionIsDev "$V"; then
    echo "$V is not a releasable version" >&2
    exit 1
  elif versionIsPreview "$V"; then
    echo "$(majorVersionIncrement "$MAJOR")-branch"
  else
    echo "$MAJOR-branch"
  fi
}

# ** git

# Does the named branch exist in this git repo ?
gitBranchExists() {
  B="$1"
  git branch -l "$B" | grep -q "$B"
}

# Switch to the named git branch, creating it if it doesn't exist.
gitSwitchAutoCreate() {
  B="$1"
  if gitBranchExists "$B"; then
    git switch "$B"
  else
    git switch -c "$B"
  fi
}

# ** main

# Run a command with optional logging ($ECHO), dry-running ($DRY) and pausing ($PAUSE).
run() {
    if [[ -n $PAUSE ]]; then read -rp "pausing, next is: $*"
    elif [[ -n $ECHO || -n $DRY ]]; then echo "$@"
    fi
    if [[ -z $DRY ]]; then "$@"; fi
}

# Symlink important files temporarily in .relfiles/.
relfiles() {
  echo "linking important release files in .relfiles/ for convenient access..."
  mkdir -p .relfiles
  cd .relfiles
  for f in \
      ../stack.yaml \
      ../Shake.hs \
      ../CHANGELOGS.md \
      ../RELEASING.md \
      ../CHANGES.md \
      ../hledger/CHANGES.md \
      ../hledger-ui/CHANGES.md \
      ../hledger-web/CHANGES.md \
      ../hledger-lib/CHANGES.md \
      ../site/src/release-notes.md \
      ../site/src/install.md \
      ../doc/ANNOUNCE \
  ; do ln -sf $f .; done
}

# Create/switch to appropriate release branch and prepare for release.
prep() {
  VERSION="$1"
  [[ -z "$VERSION" ]] && usage
  BRANCH=$(versionReleaseBranch "$VERSION")
  COMMIT="-c"
  echo "Switching to $BRANCH, auto-creating it if needed..."
  run gitSwitchAutoCreate "$BRANCH"
  echo "Bumping all version strings to $VERSION ..."
  run ./Shake setversion "$VERSION" $COMMIT
  echo "Updating all command help texts for embedding..."
  run ./Shake cmdhelp $COMMIT
  echo "Updating all dates in man pages..."
  run ./Shake mandates
  echo "Generating all the manuals in all formats...."
  run ./Shake manuals $COMMIT
  echo "Updating CHANGES.md files with latest commits..."
  run ./Shake changelogs $COMMIT
}

# Push the current branch to the CI branches that generate platform binaries.
# Assumes the github remote is named "github".
bin() {
  run git push -f github HEAD:binaries
}

# Show last week info, useful for TWIH (sm's at least).
lastweek() {
  echo "hledger time last 7 days including today (this should be run on a Friday):"
  tt bal hledger -DTS -b '6 days ago' --drop 2
  echo
  echo "By activity type, percentage:"
  tt bal hledger -DTS -b '6 days ago' --pivot t -% -c 1% | tail +1
  echo
  echo "Time log details:"
  tt print hledger -b '6 days ago' | grep -E '^[^ ]|hledger'
  echo
  echo "main repo:"
  git log --format='%C(yellow)%cd %ad %Cred%h%Creset %s %Cgreen(%an)%Creset%C(bold blue)%d%Creset' --date=short --since="6 days ago" --reverse
  echo
  echo "site repo:"
  git -C site log --format='%C(yellow)%cd %ad %Cred%h%Creset %s %Cgreen(%an)%Creset%C(bold blue)%d%Creset' --date=short --since="6 days ago" --reverse
  echo
  echo "finance repo:"
  git -C finance log --format='%C(yellow)%cd %ad %Cred%h%Creset %s %Cgreen(%an)%Creset%C(bold blue)%d%Creset' --date=short --since="6 days ago" --reverse
  echo
}

# Show a bunch of debug message strings.
dbgstrs() {
  rg --sort path -t hs 'dbg.*?(".*")' -r '$1' -o
}

# Extract Hledger.hs examples to jargon.j.
jargon() {
  rg '^ *> (.*)' -or '$1' hledger-lib/Hledger.hs > jargon.j
}

# Extract ledger/hledger/beancount commit stats to project-commits.j.
# See also https://hledger.org/reporting-version-control-stats.html
projectcommits() {
  printf "account ledger\naccount hledger\naccount beancount\n\n" >project-commits.j
  for p in ledger hledger beancount; do git -C ../$p log --format="%cd (%h) %s%n  ($p)  1%n" --date=short --reverse >> project-commits.j; done
}

if declare -f "$1" > /dev/null; then "$@"; else usage; fi

# ** notes
# *** rerunning 
# **** creates empty doc update commits
# **** creates duplicate changelog headings
# ***** CHANGES.md's version "1.24.99.1" is not yet tagged, can't list changes
