#!/bin/sh
#
# dyne:bolic software development kit - the commandline tool
#
# Copyright (C) 2003 Denis Rojo aka jaromil <jaromil@dyne.org>
#                    Alex Gnoli aka smilzo <smilzo@sfrajone.org>
#                    Pierluigi Maori aka newmark <newmark@dyne.org>
#
# This source code is free software; you can redistribute it and/or
# modify it under the terms of the GNU Public License as published 
# by the Free Software Foundation; either version 2 of the License,
# or (at your option) any later version.
#
# This source code is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# Please refer to the GNU Public License for more details.
#
# You should have received a copy of the GNU Public License along with
# this source code; if not, write to:
# Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

PACKAGE="dyne:bolic SDK"
VERSION="0.2"
ID="\$Id$"
REPOSITORY="rsync.dyne.org::dynebolic-dev"
ISO="dynebolic-dev.iso"
PFX="." # you can change it to static path where dynesdk resides

# standard output message routines
# it's always useful to wrap them, in case we change behaviour later
notice() { echo "[*] $1"; }
act() { echo " .  $1"; }
error() { echo "[!] $1"; }
func() { if [ $DEBUG ]; then echo "[D] $1"; fi }

notice "$PACKAGE version $VERSION - software development kit"
act "Copyleft 2003-2004 by jaromil - http://dynebolic.org"
act "$ID"

OPTS=`getopt -o hvp:u:r:i:q -n 'dynesdk' -- "$@"`

#eval set -- "$OPTS"

while true; do
    case "$1" in
	-h)
	    notice "SYNOPSIS: dynesdk [-hv] [-p prefix] [-u user -h host] COMMAND"
	    act "-h     print this help"
	    act "-v     print out the version of this sdk tool"
	    act "-p     path to the sdk base directory (default ./)"
	    act "-u     username for online operations"
	    act "-r     server hosting the online sdk"
	    act "-i     dynebolic iso (default ./dynebolic-dev.iso)"
            act "-q     be quick and skip checksums and crypto sigs"
	    notice "macro COMMANDS:"
	    act "checkout: download the sdk from an online server"
	    act "commit: uploads the current sdk to the server (be careful!)"
	    act "explode: opens an existing dyne:bolic iso into an SDK"
	    act "implode: packs a dyne:bolic iso from the current SDK"
	    act "chroot: dive inside the dyne:bolic SDK"
	    act "sdk-create: a all-in-one script to"
			act "            checkout,mkiso,explode creating a dir SDK"
	    act "            WARN! for sdk-create at least 2.4G of free space needed"
	    notice "micro COMMANDS:"
	    act "mkinitrd: makes an initrd.gz of INITRD_SIZE (6000)"
	    act "mkhome: packs the home into the cdrom directory"
	    act "mkvar: packs the var into the cdrom directory"
	    act "mksquash: packs the squashed filesystem in the cdrom"
	    act "mkiso: packs the cdrom directory into a bootable iso"
	    notice "right sequence:"
	    act "To create a working SDK the right sequence is the following: "
	    act "checkout    - to get the sdk from server"
	    act "mkiso       - to create the dynebolic-iso from the checkouted sdk"
	    act "explode     - to create the sdk exploded dir"
	    act "chroot      - to enter in dynebolic for developing"
	    act "commit      - when your are ABSOLUTELY SURE that it works"
	    echo; exit 2 ;;
	-v) exit 2 ;;
	-p) PFX=$2; shift 2 ;;
	-u) USER=$2; shift 2 ;;
	-r) REPOSITORY="$2::dynebolic-dev"; shift 2 ;;
	-i) ISO="$2"; shift 2 ;;
        -q) QUICK=yes; shift 1; break ;;
	--) shift; break ;;
	*)  CMD=$1; shift 1; break ;;
    esac
done

# function to check for required softwares
check_sw() {
    func "checking existance of $1"
    CHECK_SW="`which $1`"
    if [ -z $CHECK_SW ]; then
	error "$1 not found"
	RET=0
    else
	func "$1 found in $CHECK_SW"
	RET=$CHECK_SW
    fi
}

#if [ "`whoami`" != "root" ]; then
#    error "you must be ROOT on your machine to use dyne:bolic SDK"
#    exit -1
#fi

if [ -z $PFX ]; then
    error "no SDK directory prefix configured yet, read the help"
    act "you just need to do it once, settings are then stored."
    exit 0
fi

# if this is missing, no development server can be accessed
if [ -z $RSYNC ]; then 
    check_sw "rsync";
    if [ $RET ]; then RSYNC=$RET; fi
fi
if [ -z $LYNX ]; then
    check_sw "lynx";
    if [ $RET ]; then LYNX=$RET; fi
fi
# if those are missing, the iso can't be packed
if [ -z $MKISOFS ]; then
    check_sw "mkisofs";
    if [ $RET ]; then MKISOFS=$RET; fi
fi
if [ -z $MKSQUASHFS ]; then
    check_sw "mksquashfs";
    if [ $RET ]; then MKSQUASHFS=$RET; fi
fi


########################################################################
### MICRO COMMAND FUNCTIONS
########################################################################

exinitrd() {
    act "generating initrd tree (please wait)"
    mkdir $PFX/initrd
    # TODO: controllare se l'initrd.gz esiste in cdrom
    gunzip $PFX/cdrom/dyne/initrd.gz
    mount -o loop -t ext2 $PFX/cdrom/dyne/initrd $PFX/tmp
    cp -r $PFX/tmp/* $PFX/initrd
    umount $PFX/tmp
    gzip -9 $PFX/cdrom/dyne/initrd
}

mkinitrd() {
    notice "making the initrd compressed filesystem"
   
    if [ ! -r $PFX/initrd/etc/DYNEBOLIC ]; then exinitrd; fi 

    act "setup startup files"
    if [ ! -x $PFX/../startup ]; then
      error "no startup files present in $PFX/../startup"
      error "you can place the dynebolic cvs in the parent directory"
      error "in order to automatically update from there"
      sleep 2
    else
      act "updating from cvs startup from parent directory"
      cp -f $PFX/../startup/rc.* $PFX/initrd/etc
      cp -f $PFX/../startup/inittab $PFX/initrd/etc
      cp -f $PFX/../startup/libdyne.sh $PFX/initrd/lib
    fi

    cd $PFX/initrd
    act "cleaning up configs and logs"
    rm -rf tmp/*
    rm -f etc/XF86Config
    rm -f etc/HOSTNAME etc/NETWORK
    rm -f etc/fstab
    rm -f etc/auto.removable
    rm -f boot/Xok

    cd -; cd $PFX
      
    act "generate device file"
    dd if=/dev/zero of=cdrom/dyne/initrd bs=1k count=6000
    act "formatting filesystem"
    mke2fs -m 0 -i 1024 cdrom/dyne/initrd
    act "populating initrd loopback device"
    mount -o loop,rw cdrom/dyne/initrd tmp
    cp -ra initrd/* tmp
    rm -r tmp/lost+found
    

    umount tmp
    act "tuning filesystem"
    tune2fs -c 0 -i 0 cdrom/dyne/initrd
    rm -f cdrom/dyne/initrd.gz
    gzip -9 cdrom/dyne/initrd
    act "`stat cdrom/dyne/initrd.gz`"
    cd -; sync
}

mkhome() {
    notice "packaging /home";
    cd $PFX
    tar cfz cdrom/dyne/home.tgz home
    act "`stat $PFX/cdrom/dyne/home.tgz`"
    cd -; sync
}

mkvar() {
    notice "packaging /var";
    cd $PFX
    rm var/log/dynebolic.log 1>/dev/null 2>/dev/null
    tar cfz cdrom/dyne/var.tgz var
    act "`stat cdrom/dyne/var.tgz`"
    cd -; sync
}

mksquash() {
    notice "making the /usr squashed filesystem (please wait, takes long!)"
    act "setup startup files"
    if [ ! -x $PFX/../startup ]; then
      error "no startup files present in $PFX/../startup"
      sleep 2
    else
      cp -f $PFX/../startup/usr/rc.* $PFX/usr/etc
    fi
    act "start compressing: `date`"
    $MKSQUASHFS $PFX/usr $PFX/cdrom/dyne/dynebol.sys -noappend -all-root
    chmod -x $PFX/cdrom/dyne/dynebol.sys
    act "end: `date`"
    act "`stat $PFX/cdrom/dyne/dynebol.sys`"
    sync
}

mkiso() {
    notice "making the dynebolic ISO"
    cp -f $0 $PFX/cdrom/devel/
    echo "# Forged on `hostname`.`dnsdomainname` the `date` " | tee $PFX/cdrom/dyne/VERSION
    echo "# using `$MKISOFS --version` on `uname -srm`" | tee -a $PFX/cdrom/dyne/VERSION
    echo >> $PFX/cdrom/dyne/VERSION
    DYNE_SYS_VER="`cat $PFX/usr/etc/DYNEBOLIC`"
    echo "DYNE_SYS_VER=$DYNE_SYS_VER" | tee -a $PFX/cdrom/dyne/VERSION
#    echo "MD5: `md5sum $PFX/cdrom/dyne/dynebol.sys`" | tee -a $PFX/cdrom/VERSION
#    echo >> $PFX/cdrom/VERSION
    DYNE_INITRD_VER="`cat $PFX/initrd/etc/DYNEBOLIC`"
    echo "DYNE_INITRD_VER=$DYNE_INITRD_VER" | tee -a $PFX/cdrom/dyne/VERSION
    if [ -z $QUICK ]; then
    # generate md5sum hashes and gpg signatures in separate files
      rm $PFX/cdrom/dyne/*.md5 2>/dev/null 1>/dev/null
      rm $PFX/cdrom/dyne/*.asc 2>/dev/null 1>/dev/null
      echo "please wait while generating md5 sums"
      md5sum $PFX/cdrom/dyne/dynebol.sys > $PFX/cdrom/dyne/dynebol.sys.md5
      md5sum $PFX/cdrom/dyne/initrd.gz > $PFX/cdrom/dyne/initrd.gz.md5
      echo "cryptographically signing the md5 sums"
      gpg -b -a $PFX/cdrom/dyne/dynebol.sys.md5
      gpg -b -a $PFX/cdrom/dyne/initrd.gz.md5
    fi
    echo "proceeding to pack the ISO image"
    $MKISOFS -o $PFX/$ISO -J -R -udf \
            -b isolinux/isolinux.bin -c isolinux/boot.cat \
            -no-emul-boot -boot-load-size 4 -boot-info-table \
	    $PFX/cdrom/
    act "`stat $PFX/$ISO`"
    sync
}

mount_chroot() {
    notice "mount dyne:bolic SDK into a rw root cage"
    mount -o bind $PFX/initrd $PFX/chroot
    mount -o bind $PFX/usr $PFX/chroot/usr
    mount -o bind $PFX/cdrom $PFX/chroot/mnt/dynebolic
    mount -o bind $PFX/home $PFX/chroot/home
    mount -o bind $PFX/var $PFX/chroot/var
    mount /dev/shm
    mount -o bind /dev $PFX/chroot/dev
    mount -o bind /proc $PFX/chroot/proc
    mkdir /dev/shm/tmp
} 

umount_chroot() {
    notice "unmounting dyne:bolic SDK root cage"
    umount $PFX/chroot/proc
    umount $PFX/chroot/dev
    umount $PFX/chroot/var
    umount $PFX/chroot/home
    umount $PFX/chroot/mnt/dynebolic
    umount $PFX/chroot/usr
    umount $PFX/chroot
}

########################################################################




########################################################################
### MACRO COMMAND FUNCTIONS
########################################################################

checkout() {
    notice "checkout from dyne:bolic main tree repository"
    act "this function connects online to download the development tree"
    act "access to the main tree repository is restricted to d:b developers"
    echo "---"
    if [ -z $USER ]; then
        echo "** ACCESS FOR DEVELOPERS ONLY! **"
        echo -n "User:"
        read -r USER
    fi 
    notice "logging into rsync daemon with user '$USER'"
    rsync -Parl $USER@$REPOSITORY $PFX
    echo "---"
}

commit() {
    notice "commit into dyne:bolic main tree repository"
    act "WARNING: USE THIS FUNCTION WITH EXTREME CAUTION"
    act "you are going to commit your changes in the main development tree"
    act "you are supposed to be coordinating with other developers in order"
    act "to NOT overwrite changes being done. RSYNC DOESN'T MERGES DIFFERENCES"
    act "you are warned, CURSES and BAD LUCK to you if you use this without"
    act "correctly coordinating with the rest of the developers."
    echo "---"
    if [ -z $USER ]; then
        echo "** ACCESS FOR DEVELOPERS ONLY! **"
        echo -n "User:"
        read -r USER
    fi
    notice "logging into rsync daemon with user '$USER'"
    rsync -Parl --delete $PFX/cdrom $USER@$REPOSITORY
    echo "---"
}

explode() {
    notice "creating a dyne:bolic SDK in $PFX"
    if [ ! -x $PFX ]; then
       mkdir $PFX
       if [ $? != 0 ]; then
           error "cannot create directory $PFX"
	   exit -1
       fi
       # copy this script in the new SDK, if not present
       if [ ! -x "$PFX/$0" ]; then
           cp $0 $PFX
       fi
    fi
    
    # create SDK directory structure
    mkdir $PFX/tmp 2>/dev/null 1>/dev/null
    mkdir $PFX/usr 2>/dev/null 1>/dev/null
    mkdir $PFX/chroot 2>/dev/null 1>/dev/null

    if [ ! -e $PFX/cdrom/dyne/Linux ]; then    
      act "copying iso contents into $PFX/cdrom (please wait)"
      mkdir $PFX/cdrom 2>/dev/null 1>/dev/null
      mount -o loop,ro -t iso9660 $ISO $PFX/tmp
      cp -ar $PFX/tmp/* $PFX/cdrom/
      umount $PFX/tmp 
    else
      act "skipping cdrom/ creation (allready present)"
    fi
    
    exinitrd # create initrd/ from the compressed initrd.gz

    if [ ! -e $PFX/home/.xinitrc ]; then
      act "generating home tree"
      tar xfz $PFX/cdrom/dyne/home.tgz -C $PFX
    else
      act "skipping home/ creation (allready present)"
    fi
   
    if [ ! -e $PFX/var/log ]; then
      act "generating var tree"
      tar xfz $PFX/cdrom/dyne/var.tgz -C $PFX
    else
      act "skipping var/ creation (allready present)"
    fi

    if [ ! -e $PFX/usr/etc/DYNEBOLIC ]; then
      act "generating usr tree (please wait, this takes long!)"
      # TODO: check if kernel supports squashfs (mount fails)
      mount -o loop,ro -t squashfs $PFX/cdrom/dyne/dynebol.sys $PFX/tmp
      mkdir $PFX/usr 2>/dev/null 1>/dev/null
      cp -a $PFX/tmp/* $PFX/usr
      umount $PFX/tmp
    else
      act "skipping usr/ creation (allready present)"
    fi

    #TODO: generare dynebolic-sdk.cfg con i settaggi usati e detectati 
    notice "if you don't see errors above, the SDK has been generated!"
}

implode() {
    notice "imploding dyne:bolic SDK into a bootable ISO"
    mkinitrd; sync
    mkhome; sync
    mkvar; sync
    mksquash; sync
    mkiso; sync
}

chroot() {
   if [ ! -e $PFX/chroot/usr/bin/dynesplash -a \
          -e $PFX/.chroot_mounted ]; then
      rm $PFX/.chroot_mounted
   fi

   if [ ! -e $PFX/.chroot_mounted ]; then
      mount_chroot
      touch $PFX/.chroot_mounted
   fi
   notice "to dive into the dyne:bolic environment, just type:"
   act "# chroot $PFX/chroot /bin/zsh"
}

# to add some check asking

sdkcreate() {
	notice "Creating the dynebolic sdk in $PFX"
	act "-- going to checkout the dyne-sdk"
	checkout
	act "-- going to create the dyne-sdk iso in $PFX/$ISO"
	mkiso
	act "-- going to explode the sdk in $PFX"
	#mkdir $PFX/SDK 2>/dev/null 1>/dev/null
	explode
	act "-- going to delete the iso "
	rm -f $PFX/$ISO
	notice "dyne:bolic simple development kit ready"
}


# create the temporary directory
if [ ! -x $PFX/tmp ]; then mkdir $PFX/tmp; fi

case "$CMD" in
    # macro commands
    checkout) checkout ;;
    commit) commit ;;
    explode) explode ;;
    implode) implode ;;
    chroot) chroot ;;
    sdk-create) sdk-create ;;
    # micro commands
    mkinitrd) mkinitrd ;;
    mkhome) mkhome ;;
    mkvar) mkvar ;;
    mksquash) mksquash ;;
    mkiso) mkiso ;;
    
    *) error "command \"$CMD\" not recognized"
esac

notice "bye."
exit 1
