#!/bin/sh
# Creates a gentoo stage1 tarball using a current system (no catalyst)
# Copyright (C) 2005 Meethune Bhowmick (meethune@oss-institute.org)
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#     * Redistributions of source code must retain the above copyright
#       notice, this list of conditions and the following disclaimer.
#
#     * Redistributions in binary form must reproduce the above
#       copyright notice, this list of conditions and the following
#       disclaimer in the documentation and/or other materials provided
#       with the distribution.
#
#     * Neither the name of Meethune Bhowmick nor the names of
#       its contributors may be used to endorse or promote products
#       derived from this software without specific prior written
#       permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

source /sbin/functions.sh
MAKECONF="/etc/make.conf"
## Override values in ${MAKECONF}
export CFLAGS="-Os -march=i686 -pipe"
export CONFIG_PROTECT="-*"
export CXXFLAGS="${CFLAGS}"
export FEATURES="usersandbox userpriv noman noinfo nodoc -confcache -buildpkg"
export LDFLAGS=""
export ROOT=/tmp/stage1root
export USE="-* build bzip2 nptl nptlonly"

die()
## Exit Gracefully ##
## ${1} = Error Message ##
{
    eerror "${1}"
    exit 1
}

ask()
## Interactive Input ###
## ${1} = Default value [Y/N] ##
## $(2) = Message ##
{
    DEFAULT=${1}
    MESSAGE=${2}
    
    while true
    do
        echo -n "${MESSAGE}"
        read INPUT
        if [ ! -n "${INPUT}" ]; then
            if [ ${DEFAULT} = "Y" ]; then
                return 0
            else
                return 1
            fi
        fi
        if [[ ${INPUT:0:1} == "Y" ]] || [[ ${INPUT:0:1} == "y" ]]; then
            return 0 
        elif [[ ${INPUT:0:1} == "N" ]] || [[ ${INPUT:0:1} == "n" ]]; then
            return 1
        fi
    done
}

Overlay()
## Copy/Delete overlay(s) into/from ${ROOT} ##
## ${1} = ["copy"/"delete"] ##
{
    overlayList=$(grep "^PORTDIR_OVERLAY=" ${MAKECONF} | sed 's/^.*=//;s/"//g')
    if [ ! -z "${overlayList}" ]; then
        for each in ${overlayList}
        do
            if [ "${1}" == "copy" ]; then
                ebegin "Importing ${each} into ${ROOT}"
                    rsync -aR --exclude .svn --exclude CVS "${each}" "${ROOT}"
                eend ${?} || die "rsync failed!"
            elif [ ${1} == "delete" ]; then
                ebegin "Removing ${each} from ${ROOT}"
                    rm -rf "${ROOT}${each}"
                eend ${?} || die "Cannot remove ${ROOT}${each}"
            fi
        done
        return 0
    fi
    return 1
}

genMakeConf()
## Replace Values in ${MAKECONF} with the values defined above ##
{
    exportList="CFLAGS CXXFLAGS LDFLAGS"
    cp -a ${MAKECONF} ${ROOT}/etc/
    
    echo "## Generated from buildstage1 script ##" >> "${ROOT}${MAKECONF}"
    for each in ${exportList}
    do
        sed "s/^${each}/#${each}/g" -i "${ROOT}${MAKECONF}" 
        echo "${each}=\"${!each}\"" >> "${ROOT}${MAKECONF}"
    done
}

genTarball()
## Generate a Tarball of ${ROOT} ##
{
    if ! ARCH=$(expr "${CFLAGS}" : '.*march=\(.*\) ') ; then
        if ! ARCH=$(expr "${CFLAGS}" : '.*mcpu=\(.*\) ') ; then
            ARCH=$(uname -m)
        fi
    fi
    TARFILE="stage1-${ARCH}-$(date --iso-8601 | sed 's/-//g').tar.bz2"
    DESTDIR="${PWD}"

    if ask "N" "Generate Tarball? [y/N] "; then
        echo -n "Where do you want to save the tarball? [${DESTDIR}] "
        while true
        do
            read DIR
            if [ ! -n "${DIR}" ]; then
                break
            elif [ ! -d "${DIR}" ]; then
                echo -n "${DIR} is not a directory. [${DESTDIR}] "
            else
                DESTDIR=DIR
                break
            fi
        done
    else
        ewarn "To generate a tarball:"
        ewarn "    tar cjpf ${DESTDIR}/${TARFILE} -C ${ROOT} . \ "
        ewarn "        --exclude var/tmp/* --exclude var/cache/edb/* \ "
        ewarn "        --exclude var/log/portage/* --exclude tmp/*"
        return 1
    fi

    ebegin "Generating ${DESTDIR}/${TARFILE}"
        MSG=$(tar cjpf "${DESTDIR}/${TARFILE}" -C ${ROOT} . \
        --exclude var/tmp/* --exclude var/cache/edb/* \
        --exclude var/log/portage/* --exclude tmp/*)
    eend $? || die "${MSG}"
    return 0
}

genPkgList()
## Lifted from /usr/lib/catalyst/target/stage1/build.py ##
{
    OUTPUT=$(python -OOt <<EOS
import portage
def grab_multiple(basename, locations, handler, all_must_exist=0):
    mylist = []
    for x in locations:
        mylist.append(handler(x+"/"+basename))
    return mylist
                        
def scan_profile(file):
    if "grab_stacked" in dir(portage):
        return portage.grab_stacked(file, portage.settings.profiles, \
        portage.grabfile, incremental_lines=1);
    else:
        return portage.stack_lists(grab_multiple(file, \
        portage.settings.profiles, portage.grabfile), incremental=1);

pkgs = scan_profile("packages")
buildpkgs = scan_profile("packages.build")
for idx in range(0, len(pkgs)):
    try:
        bidx = buildpkgs.index(portage.dep_getkey(pkgs[idx]))
        buildpkgs[bidx] = pkgs[idx]
        if buildpkgs[bidx][0:1] == "*":
            buildpkgs[bidx] = buildpkgs[bidx][1:]
    except: pass
for b in buildpkgs: print b
EOS)
}

prepRoot()
## Remove ${ROOT} if desired and copy misc. build files ##
{
    if [ -d ${ROOT} ]; then
	if ask "Y" "Do you want me to remove $ROOT ? [Y/n] "; then
	    rm -rf ${ROOT}
	else
	    return 1
	fi
    fi
    mkdir ${ROOT}
    if [ -d /etc/portage ]; then
	mkdir -p ${ROOT}/etc/portage
	cp -a /etc/portage ${ROOT}/etc/
	rm -f ${ROOT}/etc/portage/modules
    fi
    cp -a /etc/make.profile ${ROOT}/etc/
    Overlay "copy"
    genMakeConf
    return 0
}

## Main ##
if [ ${UID} -ne 0 ]; then
    die "You need to be root."
fi
if [ "${1}" == "-h" ]; then
    die "Usage: $(basename "${0}") [EMERGE-OPTIONS]"
fi

prepRoot
emerge --info || die "Could not get portage info!"

ebegin "Generating package list"
    if genPkgList; then
        einfo ${OUTPUT}
    else
        false
    fi
eend ${?} || die "Could not generate package list!"

if ask "Y" "Emerge packages? [Y/n] "; then
    emerge ${1} virtual/os-headers \
    && emerge ${1} --noreplace ${OUTPUT} \
    || die "Emerge failed"
    ROOT=${ROOT} gcc-config $(ROOT=/ gcc-config -c) 
fi

if ask "N" "Delete ${ROOT} overlays? [y/N] "; then
    Overlay "delete"
fi

genTarball 
exit 0

# vim:syntax=sh
# vim:sw=4:softtabstop=4:expandtab
