#!/bin/sh
# mkpkgiso, build packages ISO image.
# (C) 2007-TODAY SliTaz - GNU General Public License v3.
#
# Authors : Eric Joseph-Alexandre <erjo@slitaz.org>
#	    Pascal Bellard <pascal.bellard@slitaz.org>

VERSION=0.9

PKG_VER=$1
ROOT=/home/slitaz/iso
REPOS=/var/www/slitaz/mirror/packages/$PKG_VER
SOURCES=/var/www/slitaz/mirror/sources/packages
IFMEM_C32=/var/www/slitaz/mirror/pxe/ifmem.c32
ISO_DIR=/var/www/slitaz/mirror/iso/$PKG_VER

[ -s /etc/slitaz/mkpkgiso.conf ] && . /etc/slitaz/mkpkgiso.conf
[ -s ./mkpkgiso.conf ] && . ./mkpkgiso.conf

SORT_DIR=${ROOT}/_iso.$$
TEMP_DIR=${ROOT}/_iso.$$
SORT_FILE=${ROOT}/_sort.$$
shift
OPTIONS=$@
PKG_DIR=$TEMP_DIR/packages/$PKG_VER
SRC_DIR=$TEMP_DIR/src
LOG=$PWD/$(basename $0).log

#
VOLUME_ID="packages-${PKG_VER}"
PUBLISHER="SliTaz http://www.slitaz.org/"
IMAGE="packages-${PKG_VER}.iso"
case " $@ " in
*\ --sources\ *)
	IMAGE="sources-${PKG_VER}.iso" ;;
esac
OUTPUT="$ROOT/$IMAGE"

# Check command line option.
if [ -z $PKG_VER ]; then
	cat <<EOT
Usage: $(basename $0) <Version> 
	[--boot [--auto-install] [--loram-detect]]|--webboot] [--filter]
	[--wok] [--wok-stable] [--website] [--sources] [--dry-run]
       $(basename $0) update-hg <dir>
Example:
$(basename $0) cooking --boot --auto-install --loram-detect --filter --wok --website --sources
EOT
	exit 1
fi

# Update hg repos
if [ "$PKG_VER" == "update-hg" ]; then
	for i in $1/* ; do
		grep -qs '\[paths]' $i/.hg/hgrc || continue
		cd $i
		hg pull
		hg update
		cd - > /dev/null
	done
	exit 1
fi

# Check if we provide a valide version
if [ ! -d $REPOS ]; then
	echo "Boooh! $PKG_VER is not a valid version."
	exit 1
fi

# Status function.
status()
{
	local CHECK=$?
	echo -en "\\033[70G[ "
	if [ $CHECK = 0 ]; then
		echo -en "\\033[1;33mOK"
	else
		echo -en "\\033[1;31mFailed"
	fi
	echo -e "\\033[0;39m ]"
}

need()
{
	found=1
	for i in $@ ; do
		[ -s $i ] && continue
		echo "Missing: $i "
		found=0
	done
	[ $found -ne 0 ] && return
	status
	rm -rf $TEMP_DIR $SORT_FILE
	exit 1
}

# Create temp directory
mkdir -p $TEMP_DIR/packages/$PKG_VER
which genisoimage > /dev/null || need /usr/bin/genisoimage

# Prepare evrything for ISO

echo ""
echo "Building ISO for packages  $PKG_VER"
echo "==============================================================================="
echo -n "Creating working dir $(basename $TEMP_DIR)"
status 
echo -n "Creating symlink"
status

# Link every packages to temp dir
cd $PKG_DIR
for i in $REPOS/*
do
	ln -s $i >> $LOG 2>&1
done

echo -n "Creating install script"
# Create install script as suggested by Pascal.
cat >$TEMP_DIR/install.sh<<EOF
#!/bin/sh
#

DIR=\$(cd \$(busybox dirname \$0); pwd)

# Handle --auto-install case
if [ "\$DIR" == "/etc/init.d" ]; then
  DIR=/cdrom
  if [ ! -f /cdrom/install.sh ]; then
    mkdir /cdrom 2> /dev/null
    mount --bind /mnt /cdrom
  fi
  # Handle loram on hybrid hard disk / usb key case
  if [ ! -d /usr/bin ]; then
    echo ""
    if [ -d /.usr.rw ]; then
      echo -n "Mounting /usr read-write... "
      usr=.usr.ro
    else
      echo -n "Mounting /usr read-only... "
      usr=usr
    fi
    FS=\$DIR/usr.cromfs
    if [ -f \$FS ]; then
      /bin/cromfs-driver \$FS /\$usr -o ro,dev,suid,allow_other
    elif [ -f \$DIR/usr.sqfs ]; then
      FS=\$DIR/usr.sqfs
      mount -o loop,ro -t squashfs \$FS /\$usr
    elif [ -L /\$usr ]; then
      FS=\$DIR/usr
    fi
    status
    if [ -d /.usr.rw ]; then
      if [ -x /bin/funionfs ]; then
        /bin/funionfs -o dirs=/.usr.ro=RO:/.usr.rw -o allow_other -o suid,dev NONE /usr
      else
        /bin/mount -t aufs -o br:/.usr.rw:/.usr.ro none /usr
      fi
    fi
  fi
fi

[ -d /var/cache/tazpkg ] || mkdir -p /var/cache/tazpkg
ls -d \$DIR/packages/* > /var/lib/tazpkg/mirror
ln -fs \$DIR/packages/*/*.tazpkg /var/cache/tazpkg/
ln -fs \$DIR/packages/*/packages.* /var/lib/tazpkg
echo ""
echo "=> all $PKG_VER packages are available for tazpkg/tazpkgbox"
EOF
[ -e files.list.lzma ] && cat >>$TEMP_DIR/install.sh<<EOF
ln -fs \$DIR/packages/*/files.list.lzma /var/lib/tazpkg
EOF

status
cat > $SORT_FILE <<EOT
$SORT_DIR/install.sh -4000
$SORT_DIR/README -4000
$SORT_DIR/index.html -4000
$SORT_DIR/md5sum -4000
$SORT_DIR/style.css -4000
$SORT_DIR/images/header.png -4000
$SORT_DIR/boot/bzImage 2
$SORT_DIR/boot/rootfs.gz 1
$SORT_DIR/packages -9000
EOT
( cd $ROOT; ls $SORT_DIR/packages/*/packages* $SORT_DIR/packages/*/files.list.lzma ) | \
		awk '{ printf "%s -7000\n",$0 }' >> $SORT_FILE
chmod 755  $TEMP_DIR/install.sh

case " $OPTIONS " in
*\ --filter\ *)
	SIZE=0
	for i in *.tazpkg; do
		while read f; do
			case "$i" in
			$f*) continue 2;;
			esac
		done < packages.list
		echo -n "Filtering out $i ($(du -hs $(readlink $i) | awk '{ print $1 }'))..."
		SIZE=$(( $SIZE + $(stat -c %s $(readlink $i)) ))
		rm $i
		status
	done
	UNIT=" bytes"
	if [ $SIZE -gt 10240 ]; then
		SIZE=$(( $SIZE / 1024 ))
		UNIT="K"
	fi
	if [ $SIZE -gt 10240 ]; then
		SIZE=$(( $SIZE / 1024 ))
		UNIT="M"
	fi
	echo "$SIZE$UNIT removed.";;
esac

# Copy hg subtree
get_from_hg()
{
echo -n "Adding $2"
if [ -s /home/slitaz/$1/.hg/hgrc ]; then
	cp -a /home/slitaz/$1 $TEMP_DIR
else
	wget -q -O - http://hg.slitaz.org/$1/archive/tip.tar.bz2 | tar xjf - -C $TEMP_DIR
	mv $TEMP_DIR/$1-* $TEMP_DIR/$1
fi
status
echo "$(du -hs $TEMP_DIR/$1 | awk '{ print $1 }') used by $2."
}

for i in $OPTIONS ; do
case "$i" in
--wok)
	cat >>$TEMP_DIR/install.sh<<EOF
mkdir -p /home/slitaz
ln -s \$DIR/wok /home/slitaz
echo "=> Wok (cooking) is in /home/slitaz/wok"
EOF
	if get_from_hg wok "wok (cooking)"; then
		echo "$SORT_DIR/wok -8000" >> $SORT_FILE
	fi;;
--wok-stable)
	cat >>$TEMP_DIR/install.sh<<EOF
mkdir -p /home/slitaz
ln -s \$DIR/wok /home/slitaz
echo "=> Wok (stable) is in /home/slitaz/wok"
EOF
	if get_from_hg wok-stable "wok (stable)"; then
		mv $TEMP_DIR/wok-stable $TEMP_DIR/wok
		echo "$SORT_DIR/wok -8000" >> $SORT_FILE
	fi;;
--website)
	if get_from_hg website "web site"; then
		echo "$SORT_DIR/website -6000" >> $SORT_FILE
		cat >>$TEMP_DIR/install.sh<<EOF
echo "=> slitaz web site installed in file://\$DIR/website/index.html"
EOF
	fi;;
--sources)
	echo -n "Removing previous ISO..."
	rm -f $OUTPUT
	status
	cat >>$TEMP_DIR/install.sh<<EOF
mkdir -p /home/slitaz
ln -s \$DIR/src /home/slitaz
echo "=> sources are in /home/slitaz/src"
EOF
	mkdir -p $SRC_DIR
	cd $SRC_DIR
	for i in $SOURCES/*/*
	do
		case "$i" in
		*/md5sum) continue;;
		esac
		ln -s $i >> $LOG 2>&1
	done
	find * -not -type d | grep -v md5sum | xargs md5sum > md5sum
	echo "$(du -hs $SOURCES | awk '{ print $1 }') used by sources." ;;
esac
done

# Extract boot package function
extract_boot()
{
f=$(ls $REPOS/$1-[0-9]*.tazpkg 2> /dev/null)
[ -f "$f" ] || return 1
[ -d $TEMP_DIR/boot ] || mkdir $TEMP_DIR/boot
( cd $TEMP_DIR/boot ; cpio -i fs.cpio.gz < $f 2> /dev/null ) 
( cd $TEMP_DIR/boot ; zcat fs.cpio.gz | cpio -id 2> /dev/null )
mv $TEMP_DIR/boot/fs/boot/* $TEMP_DIR/boot
rm -rf $TEMP_DIR/boot/fs.cpio.gz $TEMP_DIR/boot/fs
return 0
}

# Build hybdrid shell/mbr boot
shhybrid() 
{
blkuuid="$(blkid $1 | sed 's/.* UUID="\([^"]*\).*/\1/')"
echo -e "#\xE4\x73\x1C\nexec sed 1,/^#@/d/^\$/q \$0" | dd of=$1 conv=notrunc 2>/dev/null
dd bs=512 seek=1 conv=notrunc of=$1 2>/dev/null <<EOT

#@
#!/bin/sh
 
dev=\$({ blkid $1; blkid; } | sed '/$blkuuid/!d;s/:.*//;q')
 
if [ -n "\$dev" ]; then
	mkdir -p /mnt/packages
	mount -t iso9660 -o loop,ro \$dev /mnt/packages
	/mnt/packages/install.sh
fi

EOT
}

# Gen boot part
BOOT_OPT=""
iso=$ISO_DIR/slitaz-$PKG_VER.iso
for i in slitaz-loram-cdrom-sqfs slitaz-$PKG_VER-loram-cdrom ; do
	isoloram=$ISO_DIR/flavors/$i.iso
	[ -s $isoloram ] && break
done
case " $OPTIONS " in
*\ --boot\ *)
	echo -n "Creating boot tree"
	need $iso
	which isoinfo > /dev/null || need /usr/bin/isoinfo
	isoinfo -R -l -i $iso | awk '/^Directory/ { path=$4 } /^-/ { print path$12  }' | while read file; do
		[ "$(basename $file)" == ".." ] && continue
		[ "$file" = "/boot/isolinux/boot.cat" ] && continue
		[ -d "$(dirname $TEMP_DIR/$file)" ] ||
			mkdir -p "$(dirname $TEMP_DIR/$file)"
		isoinfo -R -x "$file" -i $iso > "$TEMP_DIR/$file"
	done
	if [ -f "$(echo $TEMP_DIR/boot/vmlinuz*)" ]; then
		rm -f $TEMP_DIR/boot/bzImage
		ln $TEMP_DIR/boot/vmlinuz* $TEMP_DIR/boot/bzImage
	fi
	status
	BOOT_OPT="-sort $SORT_FILE -b boot/isolinux/isolinux.bin \
-c boot/isolinux/boot.cat  -no-emul-boot -boot-load-size 4 -boot-info-table"
	case " $OPTIONS " in
	*\ --auto-install\ *)
		echo -n "Enabling auto install"
		sed -i "s/rw root/rw config=LABEL=packages-$PKG_VER,install.sh root/" \
			$TEMP_DIR/boot/isolinux/*.cfg
		status
		;;
	esac
	case " $OPTIONS " in
	*\ --loram-detect\ *)
		echo -n "Enabling loram autodetection"
		need $IFMEM_C32 $isoloram
		which isoinfo > /dev/null || need /usr/bin/isoinfo
		cp $IFMEM_C32 "$TEMP_DIR/boot/isolinux"
		isoinfo -R -x "/usr.sqfs" -i $isoloram \
			> "$TEMP_DIR/usr.sqfs" 2> /dev/null
		if [ -s "$TEMP_DIR/usr.sqfs" ]; then
			echo "$SORT_DIR/usr.sqfs -5000" >> $SORT_FILE
		else
			rm -f "$TEMP_DIR/usr.sqfs"
			isoinfo -R -x "/rootfs.gz" -i $isoloram \
				> "$TEMP_DIR/rootfs.gz" 2> /dev/null
			echo "$SORT_DIR/rootfs.gz -5000" >> $SORT_FILE
		fi
		isoinfo -R -x "/boot/rootfs.gz" -i $isoloram > \
			"$TEMP_DIR/boot/loram.gz"
		cat >> $TEMP_DIR/boot/isolinux/common.cfg <<EOT
label noram
        config noram.cfg
EOT
		cat >> $TEMP_DIR/boot/isolinux/noram.cfg <<EOT
display isolinux.msg
say Not enough RAM to boot slitaz.
default reboot
label reboot
        com32 reboot.c32

implicit 0
prompt 1
timeout 80
F1 help.txt
F2 options.txt
F3 isolinux.msg
F4 display.txt
F5 enhelp.txt
F6 enopts.txt
EOT
		sed -i -e 's|kernel /boot/bzImage|kernel /boot/isolinux/ifmem.c32\n\tappend 160768 core 29696 loram noram\n|' \
			-e "s|\\(.*/\\)rootfs\\(.gz .*\\)\$|label core\\n\\tkernel /boot/bzImage\\n\\1rootfs\\2\\n\\nlabel loram\\n\\tkernel /boot/bzImage\\n\\1loram\\2 loram=LABEL=packages-$PKG_VER,|" \
			$TEMP_DIR/boot/isolinux/*.cfg
		status
		;;
	esac
	echo "$SORT_DIR/boot 0" >> $SORT_FILE
	;;
*\ --webboot\ *)
	if extract_boot gpxe; then
	echo -n "Creating web boot tree"
	which isoinfo > /dev/null || need /usr/bin/isoinfo
	mkdir $TEMP_DIR/boot/isolinux/
	isoinfo -R -x "/boot/isolinux/isolinux.bin" -i $iso > \
		$TEMP_DIR/boot/isolinux/isolinux.bin
	mv $TEMP_DIR/boot/gpxe $TEMP_DIR/boot/isolinux
	echo "$SORT_DIR/boot 0" >> $SORT_FILE
	cat > $TEMP_DIR/boot/isolinux/isolinux.cfg <<EOT
default gpxe
append http://mirror.slitaz.org/pxe/pxelinux.0
EOT
	status
	BOOT_OPT="-sort $SORT_FILE -b boot/isolinux/isolinux.bin \
-c boot/isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table"
	fi
	;;
esac

if [ -n "$BOOT_OPT" ]; then
	echo "$(du -chs $TEMP_DIR/boot $TEMP_DIR/usr.sqfs 2> /dev/null | \
		    awk 'END { print $1 }') used by boot."
fi

case " $OPTIONS " in
*\ --dry-run\ *)
	echo "Please check and remove $TEMP_DIR and $SORT_FILE"
	exit
	;;
esac
# Gen ISO
echo -n "Generating iso image"
genisoimage -R -J -f -V $VOLUME_ID \
 -P "$PUBLISHER" -md5-list $REPOS/packages.md5 \
 -quiet -o $OUTPUT $BOOT_OPT $TEMP_DIR
status 

echo "$(du -hs $OUTPUT | awk '{ print $1 }') used by iso image."

cd ${ROOT}
echo -n "Creating hybrid DVD/CDROM"
which isohybrid > /dev/null && isohybrid $IMAGE 2> /dev/null
status

echo -n "Creating hybrid shell/mbr"
shhybrid $IMAGE
status

echo -n "Calculating md5sum"
md5sum $IMAGE > $(basename $IMAGE .iso).md5
status

echo -n "Moving file to mirror"
mv $IMAGE $ISO_DIR
mv $(basename $IMAGE .iso).md5 $ISO_DIR
status

# Cleaning temp files
rm -rf $TEMP_DIR $SORT_FILE

