#!/bin/sh
#
# Copyright (C) 2010 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# build-platforms.sh
#
# This tool is used when packaging a new release, or when developing
# the NDK itself. It will populate DST ($NDK/platforms by default)
# with the content of SRC ($NDK/../development/ndk/platforms/ by default).
#
# The idea is that the content of $SRC/android-N/ only contains stuff
# that is relevant to API level N, and not contain anything that is already
# provided by API level N-1, N-2, etc..
#
# More precisely, for each architecture A:
#  $SRC/android-N/include        --> $DST/android-N/arch-A/usr/include
#  $SRC/android-N/arch-A/include --> $DST/android-N/arch-A/usr/include
#  $SRC/android-N/arch-A/lib     --> $DST/android-N/arch-A/usr/lib
#
# For backwards compatibility:
#  $SRC/android-N/arch-A/usr/include --> $DST/android-N/arch-A/usr/include
#  $SRC/android-N/arch-A/usr/lib     --> $DST/android-N/arch-A/usr/lib
#
# Repeat after that for N+1, N+2, etc..
#

. `dirname $0`/../core/ndk-common.sh

# Return the list of platform supported from $1/platforms
# as a single space-separated list of levels. (e.g. "3 4 5 8 9")
# $1: source directory
extract_platforms_from ()
{
    if [ -d "$1" ] ; then
        (cd "$1/platforms" && ls -d android-*) | sed -e "s!android-!!" | tr '\n' ' '
    else
        echo ""
    fi
}

# Remove trailing path of a path
# $1: path
remove_trailing_slash () {
    echo $1 | sed -e 's!/$!!g'
}

# Reverse a file path directory
# foo -> .
# foo/bar -> ..
# foo/bar/zoo -> ../..
reverse_path ()
{
    local path cur item
    path=`remove_trailing_slash $1`
    cur="."
    if [ "$path" != "." ] ; then
        for item in `echo "$path" | tr '/' ' '`; do
            cur="../$cur"
        done
    fi
    echo `echo $cur | sed -e 's!/.$!!g'`
}

test_reverse_path ()
{
    rr=`reverse_path $1`
    if [ "$rr" != "$2" ] ; then
        echo "ERROR: reverse_path '$1' -> '$rr' (expected '$2')"
    fi
}

test_reverse_path . .
test_reverse_path ./ .
test_reverse_path foo ..
test_reverse_path foo/ ..
test_reverse_path foo/bar ../..
test_reverse_path foo/bar/ ../..
test_reverse_path foo/bar/zoo ../../..
test_reverse_path foo/bar/zoo/ ../../..

SRCDIR="../development/ndk"
DSTDIR="$ANDROID_NDK_ROOT"

ABIS="arm"
PLATFORMS=`extract_platforms_from "$SRCDIR"`

OPTION_HELP=no
OPTION_PLATFORMS=
OPTION_SRCDIR=
OPTION_DSTDIR=
OPTION_NO_SAMPLES=no
OPTION_NO_SYMLINKS=no

VERBOSE=no
VERBOSE2=no

for opt do
  optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
  case "$opt" in
  --help|-h|-\?) OPTION_HELP=yes
  ;;
  --verbose)
    if [ "$VERBOSE" = "yes" ] ; then
        VERBOSE2=yes
    else
        VERBOSE=yes
    fi
    ;;
  --src-dir=*)
    OPTION_SRCDIR="$optarg"
    ;;
  --dst-dir=*)
    OPTION_DSTDIR="$optarg"
    ;;
  --platform=*)
    OPTION_PLATFORM=$optarg
    ;;
  --abi=*)
    OPTION_ABI=$optarg
    ;;
  --no-samples)
    OPTION_NO_SAMPLES=yes
    ;;
  --no-symlinks)
    OPTION_NO_SYMLINKS=yes
    ;;
  *)
    echo "unknown option '$opt', use --help"
    exit 1
  esac
done

if [ $OPTION_HELP = "yes" ] ; then
    echo "Collect files from an Android NDK development tree and assemble"
    echo "the platform files appropriately into a final release structure."
    echo ""
    echo "options:"
    echo ""
    echo "  --help             Print this message"
    echo "  --verbose          Enable verbose messages"
    echo "  --src-dir=<path>   Source directory for development platform files [$SRCDIR]"
    echo "  --dst-dir=<path>   Destination directory [$DSTDIR]"
    echo "  --platform=<list>  Space-separated list of API levels [$PLATFORMS]"
    echo "  --abi=<list>       Space-separated list of ABIs [$ABIS]"
    echo "  --no-samples       Ignore samples"
    echo "  --no-symlinks      Don't create symlinks, copy files instead"
    echo ""
    exit 0
fi

if [ -n "$OPTION_SRCDIR" ] ; then
    SRCDIR="$OPTION_SRCDIR";
    if [ ! -d "$SRCDIR" ] ; then
        echo "ERROR: Source directory $SRCDIR does not exist !"
        exit 1
    fi
    if [ ! -d "$SRCDIR/platforms/android-3" ] ; then
        echo "ERROR: Invalid source directory: $SRCDIR"
        echo "Please make sure it contains platforms/android-3 etc..."
        exit 1
    fi
else
    SRCDIR=`dirname $ANDROID_NDK_ROOT`/development/ndk
    log "Using source directory: $SRCDIR"
fi

if [ -n "$OPTION_PLATFORM" ] ; then
    PLATFORMS="$OPTION_PLATFORM"
else
    # Build the list from the content of SRCDIR
    PLATFORMS=`extract_platforms_from "$SRCDIR"`
    log "Using platforms: $PLATFORMS"
fi


if [ -n "$OPTION_DSTDIR" ] ; then
    DSTDIR="$OPTION_DSTDIR"
else
    log "Using destination directory: $DSTDIR"
fi

if [ -n "$OPTION_ABI" ] ; then
    ABIS="$OPTION_ABI"
fi

log "Checking source platforms."
for PLATFORM in $PLATFORMS; do
    DIR="$SRCDIR/platforms/android-$PLATFORM"
    if [ ! -d $DIR ] ; then
        echo "ERROR: Directory missing: $DIR"
        echo "Please check your --platform=<list> option and try again."
        exit 2
    else
        log "  $DIR"
    fi
done

log "Checking source platform ABIs."
BAD_ABIS=
for ABI in $ABIS; do
    eval CHECK_$ABI=no
done
for PLATFORM in $PLATFORMS; do
    for ABI in $ABIS; do
        DIR="$SRCDIR/platforms/android-$PLATFORM/arch-$ABI"
        if [ -d $DIR ] ; then
            log "  $DIR"
            eval CHECK_$ABI=yes
        fi
    done
done

BAD_ABIS=
for ABI in $ABIS; do
    CHECK=`var_value CHECK_$ABI`
    log "  $ABI check: $CHECK"
    if [ "$CHECK" = no ] ; then
        if [ -z "$BAD_ABIS" ] ; then
            BAD_ABIS=$ABI
        else
            BAD_ABIS="$BAD_ABIS $ABI"
        fi
    fi
done

if [ -n "$BAD_ABIS" ] ; then
    echo "ERROR: Source directory doesn't support these ABIs: $BAD_ABIS"
    exit 3
fi

# $1: source directory (relative to $SRCDIR)
# $2: destination directory (relative to $DSTDIR)
# $3: description of directory contents (e.g. "sysroot" or "samples")
copy_src_directory ()
{
    local SDIR="$SRCDIR/$1"
    local DDIR="$DSTDIR/$2"
    if [ -d "$SDIR" ] ; then
        log "Copying $3 from \$SRC/$1 to \$DST/$2."
        mkdir -p "$DDIR" && (cd "$SDIR" && tar chf - *) | (tar xf - -C "$DDIR")
        if [ $? != 0 ] ; then
            echo "ERROR: Could not copy $3 directory $SDIR into $DDIR !"
            exit 5
        fi
    fi
}

# Create a symlink-copy of directory $1 into $2
# This function is recursive.
#
# $1: source directory (relative to $SRCDIR)
# $2: destination directory (relative to $DSTDIR)
symlink_src_directory ()
{
    local files subdirs file subdir rev
    mkdir -p "$DSTDIR/$2"
    files=`cd $DSTDIR/$1 && ls -1p | grep -v -e '.*/'`
    subdirs=`cd $DSTDIR/$1 && ls -1p | grep -e '.*/' | sed -e 's!/$!!g'`
    rev=`reverse_path $1`
    for file in $files; do
        ln -s $rev/$1/$file $DSTDIR/$2/$file
    done
    for subdir in $subdirs; do
        symlink_src_directory $1/$subdir $2/$subdir
    done
}

# Copy platform sysroot and samples into your destination
#

# $SRC/android-$PLATFORM/include --> $DST/platforms/android-$PLATFORM/arch-$ABI/usr/include
# $SRC/android-$PLATFORM/arch-$ABI/include --> $DST/platforms/android-$PLATFORM/arch-$ABI/usr/include
# for compatibility:
# $SRC/android-$PLATFORM/arch-$ABI/usr/include --> $DST/platforms/android-$PLATFORM/arch-$ABI/usr/include



# $SRC/android-$PLATFORM/arch-$ABI/usr --> $DST/platforms/android-$PLATFORM/arch-$ABI/usr
# $SRC/android-$PLATFORM/samples       --> $DST/samples
#
rm -rf $DSTDIR/platforms && mkdir -p $DSTDIR/platforms
PREV_PLATFORM_DST=
for PLATFORM in $PLATFORMS; do
    NEW_PLATFORM=platforms/android-$PLATFORM
    PLATFORM_SRC=$NEW_PLATFORM
    PLATFORM_DST=$NEW_PLATFORM
    dump "Copying android-$PLATFORM platform files"
    if [ -n "$PREV_PLATFORM_DST" ] ; then
        if [ "$OPTION_NO_SYMLINKS" = "yes" ] ; then
            log "Copying \$DST/$PREV_PLATFORM_DST to \$DST/$PLATFORM_DST"
            #cp -r $DSTDIR/$PREV_PLATFORM_DST $DSTDIR/$PLATFORM_DST
            copy_directory "$DSTDIR/$PREV_PLATFORM_DST" "$DSTDIR/$PLATFORM_DST"
        else
            log "Symlink-copying \$DST/$PREV_PLATFORM_DST to \$DST/$PLATFORM_DST"
            symlink_src_directory $PREV_PLATFORM_DST $PLATFORM_DST
        fi
        if [ $? != 0 ] ; then
            echo "ERROR: Could not copy previous sysroot to $DSTDIR/$NEW_PLATFORM"
            exit 4
        fi
    fi
    for ABI in $ABIS; do
        SYSROOT=arch-$ABI/usr
        log "Copy $ABI sysroot files from \$SRC/android-$PLATFORM over \$DST/android-$PLATFORM/arch-$ABI"
        copy_src_directory $PLATFORM_SRC/include           $PLATFORM_DST/$SYSROOT/include "sysroot headers"
        copy_src_directory $PLATFORM_SRC/arch-$ABI/include $PLATFORM_DST/$SYSROOT/include "sysroot headers"
        copy_src_directory $PLATFORM_SRC/arch-$ABI/lib     $PLATFORM_DST/$SYSROOT/lib "sysroot libs"
        copy_src_directory $PLATFORM_SRC/$SYSROOT          $PLATFORM_DST/$SYSROOT "sysroot"
    done
    PREV_PLATFORM_DST=$PLATFORM_DST
done

if [ "$OPTION_NO_SAMPLES" = no ] ; then
    # Copy platform samples and generic samples into your destination
    #
    # $SRC/samples/ --> $DST/samples/
    # $SRC/android-$PLATFORM/samples/ --> $DST/samples
    #
    dump "Copying generic samples"
    rm -rf $DSTDIR/samples && mkdir -p $DSTDIR/samples
    copy_src_directory  samples samples samples

    for PLATFORM in $PLATFORMS; do
        dump "Copy android-$PLATFORM samples"
        # $SRC/platform-$PLATFORM/samples --> $DST/samples
        copy_src_directory platforms/android-$PLATFORM/samples samples samples
    done

    # Cleanup generated files in samples
    rm -rf "$DSTDIR/samples/*/obj"
    rm -rf "$DSTDIR/samples/*/libs"
fi

log "Done !"
