#! /usr/bin/env bash

# Upgrade remote packages in a bdep-managed build2 toolchain build,
# essentially as if by executing:
#
# bdep sync -fur && b
#
# In each project of the toolchain.
#
# Note that we can't just do that because as soon as we drop some dependency
# package, the tools (b, bppg, etc) become non-runnable (missing shared
# libraries, etc).
#
# Note also that this script expects the build system (build2) and the rest of
# the toolchain (bpkg, bdep, etc) to be built in separate build configuration
# (for example, tsan for build2 and asan for the rest).
#
# Finally, this script only upgrades the default configurations. To upgrade
# the rest you can use the normal way, for example:
#
# bdep sync -fura
#
# If the -c option is specified, then the second configuration is upgraded
# and configured but is not updated. This can be done at a later stage by
# running the build system in the configuration directory:
#
# BDEP_SYNC=0 b
#
trap "exit 1" ERR
set -o errtrace # Trap in functions.

function info () { echo "$*" 1>&2; }
function error () { info "$*"; exit 1; }

# Make sure the build2 tools are runnable.
#
b    --version >/dev/null
bpkg --version >/dev/null
bdep --version >/dev/null

configure_only=

while [ $# -gt 0 ]; do
  case $1 in
    -c)
      configure_only=--configure-only
      shift
      ;;
    *)
      error "unexpected $1"
      ;;
  esac
done

# Get the configuration directories.
#
bcfg="$(b info: build2/ | sed -n -re 's/^out_root: (.+)$/\1/p')"
pcfg="$(b info: bpkg/   | sed -n -re 's/^out_root: (.+)$/\1/p')"

if [ -z "$bcfg" -o -z "$pcfg" ]; then
  error "unable to determine build configuration directories"
fi

bcfg="$(dirname "$bcfg")"
pcfg="$(dirname "$pcfg")"

if [ "$bcfg" = "$pcfg" ]; then
  error "build2 and bpkg build configuration directories are the same"
fi

# The plan is as follows:
#
# 0. First, make backup copies of both configurations. If something goes wrong,
#    it's likely the tools will be left in a non-runnable state.
#
# 1. Next, install the build system on the side and then upgrade the build
#    system configuration using that plus the existing bpkg/bdep.
#
# 2. Finally, upgrade the rest. Note that we only have one shot at this since
#    we are running bpkg that is being upgraded.
#

# Step 0.
#
if test -e "$bcfg.bak"; then
  error "$bcfg.bak already exist"
fi

if test -e "$pcfg.bak"; then
  error "$pcfg.bak already exist"
fi

set -x

cp -rp "$bcfg" "$bcfg.bak"
cp -rp "$pcfg" "$pcfg.bak"

# Step 1.
#

BDEP_SYNC=0 b "$bcfg"/libbutl/libbutl/hxx{version}
BDEP_SYNC=0 b "$bcfg"/build2/libbuild2/hxx{version}

BDEP_SYNC=0 bpkg install -d "$bcfg" \
  config.install.root=/tmp/build2-install \
  config.bin.rpath=/tmp/build2-install/lib \
  build2

/tmp/build2-install/bin/b --version >/dev/null

bpkg fetch -d "$bcfg"
BDEP_SYNC=0 bpkg build -d "$bcfg" --build /tmp/build2-install/bin/b --keep-out -ur

b --version >/dev/null

b build2/ # Should be a noop.

rm -rf /tmp/build2-install

# Step 2.
#
bpkg fetch -d "$pcfg"
BDEP_SYNC=0 bpkg build -d "$pcfg" --keep-out -ur $configure_only

if [ -z "$configure_only" ]; then

  bpkg --version >/dev/null
  bdep --version >/dev/null

  b bpkg/ bdep/ # Should be a noop.

fi

rm -rf "$bcfg.bak"
rm -rf "$pcfg.bak"