#!/bin/sh

. "`functions.locate`" || exit 1

_Version=0.7
HD=$HOME/hasher
NEEDS="vim-console less rpm-utils patchutils zsh bison flex ctags unzip wget git-core"
RCS=".vim .vimrc .zprofile .zsh_aliases .zshenv .zsh_bind .zshrc .dirc* bin/mkhasher.buildreq bin/gnuls bin/undeb .pythonstartup .inputrc .grep_colors .rpmmacros"
CACHED=".viminfo .zsh_history .history .bash_history"
SH="$SHELL"
SOPT=""
INIT=""
APTCONF=""
COPY=""
ARCH=""
BRANCH=""
TARGET=""
ADDREPO=""
SHOPT=""
HSHOPT=""
ARCHS="i586 x86_64"
REPOS="Sisyphus"
REPOROOT="/mnt/net/space/ALT"
REPOSITE="rsync://mirror.yandex.ru/altlinux"
APTCONFD="$HOME/.apt"
GITALTTASK=http://git.altlinux.org/repo
MOUNTS="/proc" #,/dev/pts";;
BUPDIR="$HOME/.cache/$_Me"
RHOME="/usr/src"
export share_network="1"

test -r "$_RC" && . "$_RC" || :
test -d "$BUPDIR" || mkdir -p "$BUPDIR"

DEFBR="${REPOS%% *}"

apt_gen_config() { # DIR
local DIR="${1?No DIR in apt_gen_config}"
      mkdir -p "$DIR/lists/partial" "$DIR/archives/partial"
      # TODO parametrize this
      cp "/etc/apt/pkgpriorities" "$DIR"
      cat > "$DIR/config" <<-@@@
	Dir::Cache "$DIR";
	Dir::State "$DIR";
	Dir::Etc "$DIR";
	Dir::Etc::SourceParts "/var/empty";
@@@
}

apt_gen() {
  local A R DIR
  for A in $ARCHS
  do
    for R in $REPOS
    do
      DIR="$APTCONFD/$A/$R"
      apt_gen_config "$DIR"
      test -d "$REPOROOT/$R/$A" && SRC="file:$REPOROOT/$R" || SRC="$REPOSITE/$R"
      cat > "$DIR/sources.list" <<-@@@
        rpm $SRC $A classic debuginfo
        rpm $SRC noarch classic
@@@
      test -d "$REPOROOT/$R/$A" || apt-get -c "$DIR/config" update
    done
  done
}

PkgFilter() { # <regexp to apt-cache search> [<regexp to filter> [<regexp to skip>]]
  apt-cache ${APTCONF:+-c $APTCONFD/$ARCH/$BRANCH/config} search "$1" |
  cut -d\  -f1 | egrep -- "${2:--devel}" | egrep -v -- "${3:-i586-|-debuginfo}" 
}

PkgGroup_X() { echo xorg-util-macros; PkgFilter "^(xorg|lib[Xx]|libcairo)" "-devel" "xerces|i586-|-debuginfo"; }
PkgGroup_I() { echo "ImageMagick"; PkgFilter "lib(png-|jpeg|tiff|gif)" "-(devel|utils)"; }
PkgGroup_S() { PkgGroup_C; PkgFilter libSDL; }
PkgGroup_C() { echo "gcc-c++ zlib-devel"; }
PkgGroup_B() { PkgFilter boost-; }
PkgGroup_A() { PkgFilter "lib.*(theora|ogg|vorbis|alut|openal-|alsa|aubio)|libmad" "" "salsa|i586-|libtelepathy|mono|-debuginfo|-doc"; }
PkgGroup_M() { echo "cmake scons premake bmake"; }
PkgGroup_G() { echo "gnome-libs-devel libgtk+2-devel libgtk+3-devel"; }
PkgGroup_Q() { PkgGroup_C; echo "qt4-devel"; }
PkgGroup_K() { echo "kde4-devel"; }

Pkg_Help="X	X11	X11 development environment
B	Boost	Boost development environment
C	C++	C++ development environment
S	SDL	SDL development environment
A	Audio	A set of audio development libraries and headers
M	Make	Make-like tools
G	Gnome	Gnome and Gtk2/3 development environment
Q	Qt4	Qt4 development environment (use -ilibqt3-devel for Qt3)
K	KDE4	KDE4 development environment
I	Image	Image processing
?	Help	Show groups content"

Pkg_Help_list() {
  echo "$Pkg_Help" | while read a b c; do
  	test "$a" != "?" && echo "$a	$b	$c
:$(eval PkgGroup_$a | tr '\n' ' ')"
done
}

_MakeHelp 'Create/modify/use hasher environment' '[files]' "
	Package group names (use -i+GROUP syntax):
$Pkg_Help

REPO can be git.alt task number,
in this case 'rpm $GITALTTASK/<task> <arch/noarch> task' is used"

while getopts ":$_Options" opt
do
  case $opt in
    B)	# Choose a BRANCH (use '?' or 'list' to list branches configured)
    	BRANCH="$OPTARG"; ARCH=${ARCH:-`arch`};;
    4)	# Use i586 architecture
    	ARCH="i586"; BRANCH="${BRANCH:-$DEFBR}";;
    6)	# Use x86_64 architecture
    	ARCH="x86_64"; BRANCH="${BRANCH:-$DEFBR}";;
    R)	# Use additional REPO string for sources.list
	BRANCH="${BRANCH:-$DEFBR}"; ARCH=${ARCH:-`arch`}
	case "$OPTARG" in
	  [0-9]*) OPTARG="rpm $GITALTTASK/$OPTARG $ARCH task
	    rpm $GITALTTASK/$OPTARG noarch task";;
	esac # This esac doesn't ends option case
        ADDREPO="$ADDREPO
	$OPTARG"
	SH="";
	;;
    w)	# Do not use local built stuff
        HSHOPT="$HSHOPT --without-stuff" ;;
    s)	# Enter an environment
    	SH="$SHELL" ;;
    S)	# Enter an environment running SHELL
        test -x "$HD/chroot$OPTARG" && SH="$OPTARG" || \
	  { test -x "$HD/chroot/bin/$OPTARG" && SH="/bin/$OPTARG"; } || \
	  _Error "No $OPTARG in $HD/chroot" ;;
    r)	# Enter an environment as root
    	SHOPT="$SHOPT --rooter";;
    p)	# Do not mount /proc into hasher environment
    	MOUNTS="";;
    P)	# Specify mounpoints LIST to pass with hsh-shell
    	MOUNTS="$OPTARG";;
    Y)	# Make an environment X11-capable
	NEEDS="$NEEDS xauth"; SHOPT="$SHOPT -Y"; SH="$SHELL" ;;
    N)	# Turn network sharing off
      	export share_network="";;
    i)	# Install packages and package groups from LIST
    	for T in $OPTARG; do 
	  case "$T" in 
	    "+"*) for TT in `echo $T | tr '+' ' '`; do
	      GNEEDS="$GNEEDS $(echo "$Pkg_Help" | while read a b c; do
		if [ "$TT" = $a -o "$TT" = $b ]; then
		  if [ "$a" = "?" ]; then echo Pkg_Help_list
		  else echo PkgGroup_$a; fi
		  break
		fi
	      done)"; done;;
	    *) NEEDS="$NEEDS $T";;
	  esac # This esac doesn't ends option case
	done
	SH="" ;;
    b)	# Do not copy/install/run anything (bare setup)
    	COPY=""; NEEDS=""; RCS=""; SH="" ;;
    I)	# Just initialize an environment
	INIT=1 ;;
    C)	# Copy these CONFIGS
	RCS="$RCS $OPTARG" ;;
    c)	# Copy these FILES
    	COPY="$COPY $OPTARG" ;;
    g)	# Re-generate .apt/* config and list files
    	apt_gen
	exit $? ;;
    d)	# Use PATH as hasher directory
    	HD="$OPTARG" ;;
    v)	# Increase verbosity (-vvv also implies sh -x)
	_Verb=$(($_Verb+1)) ; test "$_Verb" -lt 3 || set -x ;;
    x) 	# Turn on 'sh -x' debugging
    	set -x ;;
    h)	# Display help message
	_ExitHelp ;;
    *)  _ExitHelp "$opt" "$OPTARG" ;;
  esac
done

# TODO case $_Verb in

case "$BRANCH" in
  "") APTCONF="";;
  "?"|list|help) (cd "$APTCONFD/$ARCH"; echo * ); exit 0;;
  *) APTCONF="--apt-config $APTCONFD/$ARCH/$BRANCH/config"
     test -z "$ADDREPO" || {
       TempConf="$TMPDIR/$APTCONFD"
       rm -rf "$TempConf" && mkdir -p "$TempConf" || _Error "Cannot create $TempConf"
       apt_gen_config "$TempConf"
       cp "$APTCONFD/$ARCH/$BRANCH"/sources.list "$TempConf"
       echo "$ADDREPO" >> $TempConf/sources.list
       apt-get -c "$TempConf/config" update || {
         sed -i "/noarch task/d" $TempConf/sources.list
         apt-get -c "$TempConf/config" update
       }
       APTCONF="--apt-config $TempConf/config"
       _Msg "Hasher: $APTCONF"
       }
     ;;
esac

shift `expr $OPTIND - 1`

test -z "$ARCH" -o "$ARCH" = "`arch`" || TARGET="--target=$ARCH"

test -z "$INIT" || $ARCH hsh "$HD" $HSHOPT --initroot-only $TARGET $APTCONF

test -z "$*" || COPY="$COPY $*"

for f in $GNEEDS; do
  if [ $f = Pkg_Help_list ]; then Pkg_Help_list; exit 0; fi
  NEEDS="$NEEDS $($f)"
done

test -z "$NEEDS" || $ARCH hsh-install "$HD" $NEEDS || exit 1

rm -rf "$HD"/chroot/.in/cached
test -z "$RCS" || (
  cd $HOME
  tar cf "$HD"/chroot/.in/rcs.tar `eval ls -d $RCS || :`
  for f in $CACHED; do
    test \! -r "$BUPDIR/$f" -o -e "$HD/chroot/$RHOME/$f" || {
      mkdir -p "$HD/chroot/.in/cached"
      cp -r "$BUPDIR/$f" "$HD/chroot/.in/cached/"
    }
  done
  test -d "$HD/chroot/.in/cached" &&
  (
    cd "$HD/chroot/.in/cached"
    ls -A > .list
    tar -r -f "$HD"/chroot/.in/rcs.tar -T .list
  ) || :
  $ARCH hsh-run "$HD" -- tar -x -C "$RHOME" -f /.in/rcs.tar
)

mkdir -p "$HD"/chroot/.in/pass
test -z "$COPY" || cp -a $COPY "$HD"/chroot/.in/pass/
$ARCH hsh-run "$HD" -- find /.in/pass -maxdepth 1 -type f -exec cp {} "$RHOME"/RPM/SOURCES \;

test -z "$SH" || {
  case "$SH" in
  *zsh)
  	test -f "$HD/chroot/etc/zshrc" && hsh-run "$HD" --rooter -- sed -i 's/compinit$/compinit -u/' /etc/zshrc || :
  	test -x "$HD/chroot/bin/zsh" && SHOPT="$SHOPT --shell=/bin/zsh" || :
	hsh-run "$HD" -- sh -c 'eval "echo cd >> '"$RHOME"'/.zprofile"'
	;;
  esac
  # Hack exotic terminal types
  case "$TERM" in
    xterm-?*color) TERM=xterm-color;;
  esac
  $ARCH hsh-shell "$HD" ${MOUNTS:+--mountpoints=$MOUNTS} $SHOPT
  test -z "$RCS" || {
    echo '#!/bin/sh
    cd
    "$@"
    ' > "$HD"/chroot/.in/cdo
    echo "$CACHED" | tr ' ' '\n' | hsh-run -- sh /.in/cdo cpio -o 2>/dev/null | ( cd "$BUPDIR"; cpio --quiet -iu )
  }
}
