#! /bin/sh -e

# Copyright (C) 2007 Noah Slater <nslater@bytesexual.org>.

# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice and
# this notice are preserved.

# Bootstrap the pristine source ready for distribution.

SCRIPT_OK=0
SCRIPT_ERROR=1

CHANGELOG_PREDICATE=true

ACINCLUDE_FILE="acinclude.m4"
ACINCLUDE_IN_FILE="acinclude.m4.in"
AC_CHECK_ICU_COMPRESSED_FILE="build-contrib/ac_check_icu.m4_2007-09-12.gz"
AUTHORS_FILE="authors.xml"
BUILD_AUX_DIRECTORY="build-aux"
CHANGELOG_FILE="ChangeLog"
CONFIG_GUESS_COMPRESSED_FILE="build-contrib/config.guess_2007-09-12.gz"
CONFIG_GUESS_FILE="build-aux/config.guess"
CONFIG_SUB_COMPRESSED_FILE="build-contrib/config.sub_2007-09-12.gz"
CONFIG_SUB_FILE="build-aux/config.sub"
COPYING_FILE="COPYING"
GPL_COMPRESSED_FILE="build-contrib/gpl_2.txt.gz"
M4_DIRECTORY="m4"
M4_AC_CHECK_ICU_FILE="m4/ac_check_icu.m4"

ACLOCAL_EXECUTABLE=$(which aclocal || true)
AUTOCONF_EXECUTABLE=$(which autoconf || true)
AUTOHEADER_EXECUTABLE=$(which autoheader || true)
AUTOMAKE_EXECUTABLE=$(which automake || true)
GLIBTOOLIZE_EXECUTABLE=$(which glibtoolize || true)
LIBTOOLIZE_EXECUTABLE=$(which libtoolize || true)
SVN_EXECUTABLE=$(which svn || true)
SVK_EXECUTABLE=$(which svk || true)
SVN2CL_EXECUTABLE=$(which svn2cl || true)

SOURCE_DIRECTORY=""
REPOSITORY_CLIENT_EXECUTABLE=""
SVN_DIRECTORY=""

extract_configuration_variable () {
    # Extract variables from the local M4 configuration.

    variable_name=$1
    temporary_file=$(mktemp)
    if [ $? -ne 0 ]; then
        echo "Error: Unable to create a temporary file."
        exit $SCRIPT_ERROR
    fi
    echo "changequote(\`[', \`]')" > $temporary_file
    sed "s/m4_//" < $ACINCLUDE_IN_FILE >> $temporary_file
    echo $variable_name >> $temporary_file
    m4 $temporary_file | grep -v "^$"
    rm -f $temporary_file
}

display_version () {
    # Display version and copyright information.

    package_name=$(extract_configuration_variable LOCAL_PACKAGE_NAME)
    version=$(extract_configuration_variable LOCAL_VERSION)
    cat << EOF
bootstrap - $package_name $version

Copyright (C) 2007 Noah Slater <nslater@bytesexual.org>.

Copying and distribution of this script, with or without modification, are
permitted in any medium without royalty provided the copyright notice and this
notice are preserved.

Written by Noah Slater <nslater@bytesexual.org>.
EOF
}

display_help () {
    # Display a short description of the script's behaviour.

    list_address=$(extract_configuration_variable LOCAL_LIST_ADDRESS)
    list_uri=$(extract_configuration_variable LOCAL_LIST_URI)
    cat << EOF
Usage: $1 [OPTION]...

The $basename script bootstraps the pristeen source so that it can be built.

The exit status is 0 for success or 1 for failure.

Options:

  -h  display a short help message and exit
  -v  display version information and exit
  -C  do not generate a ChangeLog from Subversion

Report bugs via the web at <$list_uri>.

Report bugs via email to <$list_address>.
EOF
}

display_error () {
    # Display a short instruction referring users to further documentation.

    echo "Try \`"$1" -h' for more information."
}

get_svk_svn_directory () {
    # Return the SVN repository directory for a SVK checkout directory.

    depot_directory=$1
    svk depotmap --list | grep "^/" | while read depot_map; do
        depot_name=$(echo $depot_map | awk "{print \$1}")
        repository_directory=$(echo $depot_map | awk "{print \$2}")
        if echo $depot_directory | grep "^"$depot_name > /dev/null; then
            echo $depot_directory | \
                sed "s|"$depot_name"|file://"$repository_directory"/|"
        fi
    done
}

set_repository_client_executable () {
    # Set the REPOSITORY_CLIENT_EXECUTABLE variable.

    if test -n "$SVN_EXECUTABLE" \
        -a -n "$($SVN_EXECUTABLE info . 2> /dev/null)"; then
        REPOSITORY_CLIENT_EXECUTABLE=$SVN_EXECUTABLE
    else
        if test -n "$SVK_EXECUTABLE" \
            -a -n "$($SVK_EXECUTABLE info . 2> /dev/null)"; then
            REPOSITORY_CLIENT_EXECUTABLE=$SVK_EXECUTABLE
        fi
    fi  > /dev/null
}

set_svn_directory () {
    # Set the Subversion directory for a directory.

    if test "$REPOSITORY_CLIENT_EXECUTABLE" = "$SVN_EXECUTABLE"; then
        SVN_DIRECTORY="."
    fi
    if test "$REPOSITORY_CLIENT_EXECUTABLE" = "$SVK_EXECUTABLE"; then
        depot_directory=$(svk info . | \
            grep "Depot Path" | awk "{print \$3}")
        SVN_DIRECTORY=$(get_svk_svn_directory $depot_directory)
    fi
}

generate_dummy_changelog () {
    # Generate a dummy ChangLog file.

    echo "Warning: Generating a dummy ChangeLog file."
    touch $CHANGELOG_FILE
}

check_svn_environment () {
    # Check the Subversion environment for sanity.

    if test -z "$SVN_EXECUTABLE" -a -z "$SVK_EXECUTABLE"; then
        echo "Warning: Unable to find the svn or svk commands."
        return $SCRIPT_ERROR
    fi
    set_repository_client_executable
    set_svn_directory
    if test -z "$SVN_DIRECTORY"; then
        echo "Warning: Unable to determine repository information."
        return $SCRIPT_ERROR
    fi
}

generate_changelog () {
    # Generate the ChangLog file using the Subversion repository.

    if test -n "$SVN_DIRECTORY"; then
        if test ! -x "$SVN2CL_EXECUTABLE"; then
            echo "Warning: Unable to find the svn2cl command."
            generate_dummy_changelog
        else
            echo "Generating \`"$CHANGELOG_FILE"' (may take a while)"
            $SVN2CL_EXECUTABLE --authors=$AUTHORS_FILE $SVN_DIRECTORY
        fi
    else
        generate_dummy_changelog
    fi
}
generate_acinclude () {
    # Generate the acinclude.m4 file using the Subversion repository.

    release_code=$(sed -e "s/\[//g" -e "s/\]//g" -e "s/(//g" -e "s/)//g" \
        < $ACINCLUDE_IN_FILE | awk "/LOCAL_VERSION_STAGE, /{print \$2}")
    if test -z "$SVN_DIRECTORY" -o -z "$release_code"; then
        sed "s/%release%//" < $ACINCLUDE_IN_FILE > $ACINCLUDE_FILE
    else
        if test "$REPOSITORY_CLIENT_EXECUTABLE" = "$SVN_EXECUTABLE"; then
            revision_number=$($SVN_EXECUTABLE info $SVN_DIRECTORY | \
                awk "/Revision:/{print \$2}")
        fi
        if test "$REPOSITORY_CLIENT_EXECUTABLE" = "$SVK_EXECUTABLE"; then
            revision_number=$($SVK_EXECUTABLE info . | \
                awk "/Mirrored From/{print \$5}")
        fi
        sed "s/%release%/$revision_number/" \
            < $ACINCLUDE_IN_FILE > $ACINCLUDE_FILE
    fi
}

process_file_collection () {
    # Process files required to complete the bootstrap.

    echo "Installing \`"$SOURCE_DIRECTORY/$COPYING_FILE"'"
    gzip --decompress --stdout $GPL_COMPRESSED_FILE > $COPYING_FILE
    echo "Installing \`"$SOURCE_DIRECTORY/$BUILD_AUX_DIRECTORY"'"
    mkdir -p $BUILD_AUX_DIRECTORY
    echo "Installing \`"$SOURCE_DIRECTORY/$CONFIG_GUESS_FILE"'"
    gzip --decompress --stdout \
        $CONFIG_GUESS_COMPRESSED_FILE > $CONFIG_GUESS_FILE
    echo "Installing \`"$SOURCE_DIRECTORY/$CONFIG_SUB_FILE"'"
    gzip --decompress --stdout \
        $CONFIG_SUB_COMPRESSED_FILE > $CONFIG_SUB_FILE
    echo "Installing \`"$SOURCE_DIRECTORY/$M4_DIRECTORY"'"
    mkdir -p $M4_DIRECTORY
    echo "Installing \`"$SOURCE_DIRECTORY/$M4_AC_CHECK_ICU_FILE"'"
    gzip --decompress --stdout \
        $AC_CHECK_ICU_COMPRESSED_FILE > $M4_AC_CHECK_ICU_FILE
}

run_aclocal () {
    # Run the correct version of aclocal.

    if test -x "$ACLOCAL_EXECUTABLE"; then
        echo "Running $ACLOCAL_EXECUTABLE"
        $ACLOCAL_EXECUTABLE -I m4
    else
        echo "Can't find aclocal"
        exit $SCRIPT_ERROR
    fi
}

run_libtoolize () {
    # Run the correct version of libtoolize.

    if test -x "$LIBTOOLIZE_EXECUTABLE"; then
        echo "Running $LIBTOOLIZE_EXECUTABLE"
        $LIBTOOLIZE_EXECUTABLE -f -c
    else
        if test -x "`which $GLIBTOOLIZE_EXECUTABLE`"; then
            echo "Running $GLIBTOOLIZE_EXECUTABLE"
            $GLIBTOOLIZE_EXECUTABLE -f -c
        else
            echo "Can't find libtoolize or glibtoolize"
            exit $SCRIPT_ERROR
        fi
    fi
}

run_autoheader () {
    # Run the correct version of autoheader.

    if test -x "$AUTOHEADER_EXECUTABLE"; then
        echo "Running $AUTOHEADER_EXECUTABLE"
        $AUTOHEADER_EXECUTABLE -f
    else
        echo "Can't find autoheader"
        exit $SCRIPT_ERROR
    fi
}

run_automake () {
    # Run the correct version of automake.

    AUTOMAKE_OPTION_COLLECTION=""
    if test -x "$AUTOMAKE_EXECUTABLE"; then
        echo "Running $AUTOMAKE_EXECUTABLE"
        $AUTOMAKE_EXECUTABLE -f -c -a --gnits
    else
        echo "Can't find automake"
        exit $SCRIPT_ERROR
    fi
}

run_autoconf () {
    # Run the correct version of autoconf.

    if test -x "$AUTOCONF_EXECUTABLE"; then
        echo "Running $AUTOCONF_EXECUTABLE"
        $AUTOCONF_EXECUTABLE -f
    else
        echo "Can't find autoconf"
        exit $SCRIPT_ERROR
    fi
}

run_command_collection () {
    # Run commands required to complete the bootstrap.

    run_libtoolize
    run_aclocal
    run_autoheader
    run_automake
    run_autoconf
}

parse_script_option_list () {
    # Parse the script option list and take the appropriate action.

    basename=$(basename $0)
    if ! argument_list=$(getopt vhC $@); then
        echo
        display_error $basename
        exit $SCRIPT_ERROR
    fi
    eval set -- "$argument_list"
    while [ $# -gt 0 ]; do
        case "$1" in
            -v)
                shift
                display_version
                exit $SCRIPT_OK
                ;;
            -h)
                shift
                display_help $basename
                exit $SCRIPT_OK
                ;;
            -C)
                shift
                CHANGELOG_PREDICATE=false
                ;;
            --)
                shift
                break
                ;;
            *)
                echo "Unknown option: $1" 1>&2
                echo
                display_error $basename
                exit $SCRIPT_ERROR
                ;;
        esac
    done
    SOURCE_DIRECTORY=$(dirname $0)
    cd $SOURCE_DIRECTORY
    process_file_collection
    check_svn_environment || true
    if test "$CHANGELOG_PREDICATE" = "true"; then
        generate_changelog
    else
        generate_dummy_changelog
    fi
    generate_acinclude
    run_command_collection
}

parse_script_option_list $@
