#!/bin/bash

export SCRIPT_DIR=$(dirname "$0")

##
## Configuration Variables
##

SCHEMES="$@"

config ()
{
    # The workspace to build.
    #
    # If not set and no workspace is found, the -workspace flag will not be passed
    # to `xctool`.
    #
    # Only one of `XCWORKSPACE` and `XCODEPROJ` needs to be set. The former will
    # take precedence.
    : ${XCWORKSPACE=$(find_pattern "*.xcworkspace")}

    # The project to build.
    #
    # If not set and no project is found, the -project flag will not be passed
    # to `xctool`.
    #
    # Only one of `XCWORKSPACE` and `XCODEPROJ` needs to be set. The former will
    # take precedence.
    : ${XCODEPROJ=$(find_pattern "*.xcodeproj")}

    # A bootstrap script to run before building.
    #
    # If this file does not exist, it is not considered an error.
    : ${BOOTSTRAP="$SCRIPT_DIR/bootstrap"}

    # Extra options to pass to xctool.
    : ${XCTOOL_OPTIONS="RUN_CLANG_STATIC_ANALYZER=NO"}

    # A whitespace-separated list of default schemes to build.
    #
    # Individual names can be quoted to avoid word splitting.
    : ${SCHEMES:=$(xcodebuild -list -project "$XCODEPROJ" 2>/dev/null | awk -f "$SCRIPT_DIR/schemes.awk")}

    # A whitespace-separated list of executables that must be present and locatable.
    : ${REQUIRED_TOOLS="xctool"}

    export XCWORKSPACE
    export XCODEPROJ
    export BOOTSTRAP
    export XCTOOL_OPTIONS
    export SCHEMES
    export REQUIRED_TOOLS
}

##
## Build Process
##

main ()
{
    config

    if [ -n "$REQUIRED_TOOLS" ]
    then
        echo "*** Checking dependencies..."
        check_deps
    fi

    if [ -f "$BOOTSTRAP" ]
    then
        echo "*** Bootstrapping..."
        "$BOOTSTRAP" || exit $?
    fi

    echo "*** The following schemes will be built:"
    echo "$SCHEMES" | xargs -n 1 echo "  "
    echo

    echo "$SCHEMES" | xargs -n 1 | (
        local status=0

        while read scheme
        do
            build_scheme "$scheme" || status=1
        done

        exit $status
    )
}

check_deps ()
{
    for tool in $REQUIRED_TOOLS
    do
        which -s "$tool"
        if [ "$?" -ne "0" ]
        then
            echo "*** Error: $tool not found. Please install it and cibuild again."
            exit 1
        fi
    done
}

find_pattern ()
{
    ls -d $1 2>/dev/null | head -n 1
}

run_xctool ()
{
    if [ -n "$XCWORKSPACE" ]
    then
        xctool -workspace "$XCWORKSPACE" $XCTOOL_OPTIONS "$@" 2>&1
    elif [ -n "$XCODEPROJ" ]
    then
        xctool -project "$XCODEPROJ" $XCTOOL_OPTIONS "$@" 2>&1
    else
        echo "*** No workspace or project file found."
        exit 1
    fi
}

parse_build ()
{
    awk -f "$SCRIPT_DIR/xctool.awk" 2>&1 >/dev/null
}

build_scheme ()
{
    local scheme=$1

    echo "*** Building and testing $scheme..."
    echo

    local sdkflag=
    local action=test

    # Determine whether we can run unit tests for this target.
    run_xctool -scheme "$scheme" run-tests | parse_build

    local awkstatus=$?

    if [ "$awkstatus" -eq "1" ]
    then
        # SDK not found, try for iphonesimulator.
        sdkflag="-sdk iphonesimulator"

        # Determine whether the unit tests will run with iphonesimulator
        run_xctool $sdkflag -scheme "$scheme" run-tests | parse_build

        awkstatus=$?

        if [ "$awkstatus" -ne "0" ]
        then
            # Unit tests will not run on iphonesimulator.
            sdkflag=""
        fi
    fi

    if [ "$awkstatus" -ne "0" ]
    then
        # Unit tests aren't supported.
        action=build
    fi

    run_xctool $sdkflag -scheme "$scheme" $action
}

export -f build_scheme
export -f run_xctool
export -f parse_build

main
