#!/bin/bash

set -e -o pipefail


### Functions

fatal_msg () {
    printf '💀💀💀 error: %s 💀💀💀\n' "$1" 1>&2
}

usage () {
    cat <<'EOF' 1>&2
Test that ch-image can upgrade storage directories generated by old versions,
i.e., unpack each old storage directory from a tarball, then try to upgrade it
and run the test suite.

Usage:

  $ old-storage.sh SCOPE WORKDIR (DIR|TAR1) [TAR2 ...]

WORKDIR is where ch-image storage are unpacked. It must be empty and have
enough space for one storage directory.

TARn are old storage directories archived as tarballs. These must have certain
properties:

  1. Named storage-$VERSION.$ARCH.tar.gz, e.g. “storage-0.27.x86_64.tar.gz”.
     (Note: $ARCH is not currently validated but may be in the future.)

  2. Is a tarbomb, e.g.:

       $ tar tf storage-0.26.x86_64.tar.gz | head -3
       ./
       ./dlcache/
       ./dlcache/alpine:3.9.fat.json

  3. The result of:

       $ rm -Rf $(ch-image storage-path) && ch-test -b ch-image build

     or equivalent, though mostly rather than fully successful tests are fine.

     Note: Best practice is to generate the tarball at the time of release,
     because old test suites often don’t pass due to changing source images.

If a directory DIR is given instead, use all tarballs in that directory that
have last-modified dates less than one year in the past. (See #1507.)
EOF
}

INFO () {
    printf '📣 %s\n' "$1"
}


### Parse arguments & setup

if [[ $1 = --help || $1 = -? ]]; then
    usage
    exit 0
fi
if [[ $# -lt 3 ]]; then
    usage
    exit 1
fi
scope=$1; shift
workdir=$1; shift

trap 'fatal_msg "command failed on line $LINENO"' ERR
PATH=$(cd "$(dirname "$0")" && pwd)/../bin:$PATH
export PATH

if [[ -d $1 ]]; then
    oldtars=$(find "$1" -mindepth 1 -mtime -365 -print | sort)
else
    oldtars=$(printf '%s ' "$@")  # https://www.shellcheck.net/wiki/SC2124
fi


### Main loop

INFO "workdir: $workdir"
for oldtar in $oldtars; do
    base=$(basename "$oldtar")
    base=${base%.*}  # rm .gz
    base=${base%.*}  # rm .tar
    base=${base%.*}  # rm architecture
    storage=${workdir}/${base}

    INFO "old tar:   $oldtar ($(stat -c %y "$oldtar"))"
    INFO "unpacking: $storage"
    [[ -d $workdir ]]
    [[ ! -d $storage ]]
    mkdir "$storage"
    tar xf "$oldtar" -C "$storage"
    [[ -d $storage ]]
    export CH_IMAGE_STORAGE=$storage
    INFO "unpacked: $(du -sh "$storage" | cut -f1) bytes in $(du --inodes -sh "$storage" | cut -f1) inodes"

    case ${storage#*-} in
        0.29|0.30|0.31)
            INFO "working around bug fixed by PR #1662"
            (cd "$storage"/bucache && git branch -D alpine+latest)
            ;;
    esac

    INFO "upgrading"
    ch-image list
    # These are images that contain references to things on the internet that
    # go out of date, so builds based on them fail. Re-pull them to get a
    # current base image.
    ch-image pull archlinux:latest

    INFO "testing"
    ch-test -b ch-image --pedantic=no -s "$scope" all

    INFO "deleting: $storage"
    rm -Rf --one-file-system "$storage"
    [[ ! -d $storage ]]
done
