#!/bin/sh
##
##  openpkg.boot -- OpenPKG bootstrap procedure (look Ma, without hands ;)
##  Copyright (c) 2000-2003 Cable & Wireless Deutschland GmbH
##  Copyright (c) 2000-2003 The OpenPKG Project <http://www.openpkg.org/>
##  Copyright (c) 2000-2003 Ralf S. Engelschall <rse@engelschall.com>
##

#   This is a very tricky procedure for building the OpenPKG bootstrap
#   package via the RPM specification openpkg.spec, but without
#   requiring that OpenPKG's RPM already exists. For this the
#   openpkg.spec file is manually executed here in order to build
#   OpenPKG RPM the first time (that is, we emulate a sufficient
#   subset of the RPM functionality), followed by a second round over
#   openpkg.spec with the real (and then existing) OpenPKG RPM tool.
#   Also keep in mind that lots of tricks are played here in order to
#   perform all the steps without having to touch the real installation
#   location. That is the whole procedure can (and should) be performed
#   by a non-priviledged user and no access to the real installation
#   location filesystem location.

me="openpkg.boot"

##
##  command line handling
##

#   command line parameters (defaults)
help=0
verbose=''
prefix=''
usr='';  grp=''
susr=''; sgrp=''
musr=''; mgrp=''
rusr=''; rgrp=''
nusr=''; ngrp=''
bs=0

#   parse command line options
for opt
do
    case $opt in
        -*=*) arg=`echo "$opt" | sed 's/^[-_a-zA-Z0-9]*=//'` ;;
           *) arg='' ;;
    esac
    case $opt in
        -h | --help          ) help=1      ;;
        -v | --verbose       ) verbose=v   ;;
        --prefix=*           ) prefix=$arg ;;
        --usr=* | --user=*   ) usr=$arg    ;;
        --grp=* | --group=*  ) grp=$arg    ;;
        --susr=*             ) susr=$arg   ;;
        --sgrp=*             ) sgrp=$arg   ;;
        --musr=*             ) musr=$arg   ;;
        --mgrp=*             ) mgrp=$arg   ;;
        --rusr=*             ) rusr=$arg   ;;
        --rgrp=*             ) rgrp=$arg   ;;
        --nusr=*             ) nusr=$arg   ;;
        --ngrp=*             ) ngrp=$arg   ;;
        -bs | -s             ) bs=1        ;;
        *                    ) help=1      ;;
    esac
done
if [ ".$bs" = .0 -a ".$prefix" = . ]; then
    help=1
fi
if [ ".$help" = .1 ]; then
    echo "Usage: sh $me [-h|--help] [-v|--verbose]" 2>&1
    echo "       --prefix=<prefix> [--user=<usr>] [--group=<grp>]" 2>&1
    echo "       [--{s,m,r,n}usr=<usr>] [--{s,m,r,n}grp=<grp>]" 2>&1
    exit 1
fi

#   determine missing parameters
eval `sh aux.usrgrp.sh \
      --usr="$usr" --grp="$grp" \
      --susr="$susr" --sgrp="$sgrp" \
      --musr="$musr" --mgrp="$mgrp" \
      --rusr="$rusr" --rgrp="$rgrp" \
      --nusr="$nusr" --ngrp="$ngrp"`

##
##  determine package information
##

name="openpkg"
spec="$name.spec"
version=`grep V_openpkg $spec | head -1 | awk '{ printf("%s", $3); }'`
release=`grep R_openpkg $spec | head -1 | awk '{ printf("%s", $3); }'`

##
##  display headline
##

sh ./shtool echo -e "%BOpenPKG Bootstrap Procedure%b"
echo "++ bootstrap version: $version-$release"
echo "++ user/group pairs: $susr/$sgrp $musr/$mgrp $rusr/$rgrp $nusr/$ngrp"

##
##   optionally roll just a bootstrap source package
##

if [ ".$bs" = .1 ]; then
    srcdir=.
    if [ -d ../../DST ]; then
       dstdir=../../DST/openpkg
    elif [ -d ../../dst ]; then
       dstdir=../../dst/openpkg
    else
       dstdir=.
    fi
    tmpdir="/tmp/$me.$$.d"
    if [ -d ../PKG/SRC ]; then
       pkgdir=../PKG/SRC
    elif [ -d ../PKG ]; then
       pkgdir=../PKG
    elif [ -d ../../PKG/SRC ]; then
       pkgdir=../../PKG/SRC
    elif [ -d ../../PKG ]; then
       pkgdir=../../PKG
    elif [ -d ../../pkg/src ]; then
       pkgdir=../../pkg/src
    elif [ -d ../../pkg ]; then
       pkgdir=../../pkg
    else
       pkgdir=..
    fi
    echo "** rolling source bootstrap package:"
    echo "   $pkgdir/$name-$version-$release.src.sh"
    rm -rf $tmpdir
    mkdir $tmpdir
    ( echo "dstdir=$dstdir"
      echo "srcdir=$srcdir"
      echo "tmpdir=$tmpdir"
      grep '^%define' $spec | sed -e 's:^%define *\([^ ]*\) *\(.*\):\1="\2":'
      grep '^Source' $spec  | sed -e 's;^Source[0-9]*: *;;' -e 's;^.*/;$dstdir/;' \
                                  -e 's;^\([^/]*\)$;$srcdir/\1;' -e 's;%;$;g' \
                                  -e 's;^\(.*\)$;cp \1 $tmpdir/;'
      echo "cp -p $spec $tmpdir/"
    ) >$tmpdir/.sh
    sh $tmpdir/.sh
    rm -f $tmpdir/.sh
    sed <$srcdir/aux.wrapsrc.sh >$pkgdir/$name-$version-$release.src.sh \
        -e "s;@DIR@;$name-$version-$release.src;" -e "s;@TGZ@;$name-$version-$release.src.tar.Z;"
    (cd $tmpdir && tar cf - *) | compress |\
    uuencode $name-$version-$release.src.tar.Z |\
        dd bs=64000 2>/dev/null >>$pkgdir/$name-$version-$release.src.sh
    exit 0
fi

##
##  calculate location id
##

prefix=`echo "$prefix" | sed -e 's;//*;/;g' -e 's;/$;;'`
if [ ".`expr $prefix : '/[^/][^/]*$'`" != .0 ]; then
    loc=`echo $prefix | cut -c2-4`
else
    loc=`echo $prefix | sed -e 's;/\(.\)[^/]*;\1;g' | cut -c1-3`
fi
echo "++ location id: $loc"

##
##  determine distribution directory
##

V_rpm=`grep V_rpm $spec | head -1 | awk '{ printf("%s", $3); }'`
if [ -f "../../DST/openpkg/rpm-${V_rpm}.tar.gz" ]; then
    distdir="`cd ../../DST/openpkg; pwd`" # developer only
else
    distdir="`pwd`"
fi
echo "++ distribution directory: $distdir"

##
##  perform prerequisite checks
##

sh ./aux.prereq.sh source

##
##  find reasonable run-time paths and tools
##

#   find reasonable temporary directory
tmpdir="/tmp"
test ".$TMPDIR"  != . && tmpdir="$TMPDIR"
test ".$TEMPDIR" != . && tmpdir="$TEMPDIR"

#   find reasonable safe program path
test ".$PATH" = . && PATH="/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin"
for dir in /usr/ccs/bin /usr/xpg4/bin; do
    test -d $dir && PATH="$PATH:$dir"
done
export PATH

#   find reasonable TAR
l_tar=''
for t in gtar tar; do
    for p in `IFS=":"; echo . $PATH`; do
        if [ -f "$p/$t" ]; then
            l_tar="$p/$t"
            break
        fi
    done
    [ ".$l_tar" != . ] && break
done
if [ ".$l_tar" = . ]; then
    echo "$0:FAILED: required TAR not found"
    exit 1
fi

#   find required Make tool
l_make=''
for t in gmake make; do
    for p in `IFS=":"; echo . $PATH`; do
        if [ -f "$p/$t" ]; then
            l_make="$p/$t"
            break
        fi
    done
    [ ".$l_make" != . ] && break
done
if [ ".$l_make" = . ]; then
    echo "$0:FAILED: required Make tool not found"
    exit 1
fi

#   find required [GNU] C Compiler
l_cc=''
for t in egcc ggcc gcc cc; do
    for p in `IFS=":"; echo . $PATH`; do
        if [ -f "$p/$t" ]; then
            # if [ ".`$p/$t --version 2>/dev/null | grep '[23]\.[789]'`" != . ]; then
                l_cc="$p/$t"
                break
            # fi
        fi
    done
    [ ".$l_cc" != . ] && break
done
if [ ".$l_cc" = . ]; then
    echo "$0:FAILED: required [GNU] C/C++ compiler not found"
    exit 1
fi

##
##  execute the spec file manually by emulating
##  the behaviour of the OpenPKG RPM tool.
##

#   create script prolog
prolog="$tmpdir/openpkg.boot.prolog.sh"
cp /dev/null $prolog
(
  echo "_specdir=`pwd`" 
  echo "_sourcedir=$distdir" 
  echo "_tmppath=$tmpdir" 
  echo "_builddir=$tmpdir" 
  echo "l_prefix=$prefix"
  echo "l_location=$loc"
  echo "l_buildroot=$tmpdir/$name-$version-root"
  echo "l_susr=$susr"
  echo "l_sgrp=$sgrp"
  echo "l_musr=$musr"
  echo "l_mgrp=$mgrp"
  echo "l_rusr=$rusr"
  echo "l_rgrp=$rgrp"
  echo "l_nusr=$nusr"
  echo "l_ngrp=$ngrp"
  echo "l_tar=$l_tar"
  echo "l_make=$l_make"
  echo "l_cc=$l_cc"
  grep '%define' $spec | \
  sed \
    -e 's:^%define *\([^ ]*\) *\(.*\):\1="\2":'
  grep "^[A-Za-z0-9]*: *" $spec | \
  sed \
    -e 's;^\([A-Za-z0-9]*\): *\(.*\)$;\1="\2";' \
    -e 's;^A;a;' -e 's;^B;b;' -e 's;^C;c;' -e 's;^D;d;' -e 's;^E;e;' \
    -e 's;^F;f;' -e 's;^G;g;' -e 's;^H;h;' -e 's;^I;i;' -e 's;^J;j;' \
    -e 's;^K;k;' -e 's;^L;l;' -e 's;^M;m;' -e 's;^N;n;' -e 's;^O;o;' \
    -e 's;^P;p;' -e 's;^Q;q;' -e 's;^R;r;' -e 's;^S;s;' -e 's;^T;t;' \
    -e 's;^U;u;' -e 's;^V;v;' -e 's;^W;w;' -e 's;^X;x;' -e 's;^Y;y;' \
    -e 's;^Z;z;' -e 's;^buildRoot;buildroot;'
  echo "RPM_BUILD_ROOT=\"%{buildroot}\""
  echo "RPM_BUILD_DIR=\"%{_builddir}\""
  echo "RPM_SOURCE_DIR=\"$distdir\""
  echo "export RPM_BUILD_ROOT"
  echo "export RPM_BUILD_DIR"
  echo "export RPM_SOURCE_DIR"
  echo "set -x"
  echo "umask 022"
  echo "cd \$RPM_BUILD_DIR"
) | sed -e 's;%{\([^}]*\)};${\1};g' >$prolog

#   install package via RPM spec file by faking a
#   sufficiently enough RPM run-time environment
runscript () {
    step=$1
    script="$tmpdir/openpkg.boot.$step.sh"
    echo ". $prolog" >$script
    sed -e "/^%$step/,/^%/ p" -e 'd' <$spec | \
    sed -e '/^%/d' | \
    sed -e 's;%{SOURCE \([^ ]*\.tar[^ ]*\)};${RPM_DIST_DIR}/\1;g' \
        -e 's;%{SOURCE \([^ ]*\)};${RPM_SOURCE_DIR}/\1;g' | \
    sed -e 's;%{[?]\([^:]*\):\([^}]*\)};${\1+\2};g' \
        -e 's;%{![?]\([^:]*\):\([^}]*\)};${\1-\2};g' \
        -e 's;%{\([^}]*\)};${\1};g' >>$script
    echo "++ executing(%$step): sh $script"
    sh $script
    if [ $? -ne 0 ]; then
        rm -f $script
        echo "$0:ERROR: script returned non-null value"
        exit 1
    fi
    rm -f $script
}
runscript prep
runscript build
runscript install

##
##  adjust build environment so that the installed
##  "rpm" is actually useable, although it still resides in
##  the temporary location instead of the real location.
##

#   suck in prolog in order to get variables from the spec file
cwd=`pwd`
. $prolog
cd $cwd

#   suck in buildenv script in order to get musr/mgrp
. $tmpdir/openpkg-*/.buildenv

#   create a custom "rpm" command
echo "++ creating custom RPM command"
rm -f $tmpdir/rpm >/dev/null 2>&1
rmdir $tmpdir/rpm >/dev/null 2>&1
if [ -d "$tmpdir/rpm" ]; then
    echo "$0:ERROR: directory $tmpdir/rpm exists, cannot create file with same name"
    exit 1
fi
if [ -f "$tmpdir/rpm" ]; then
    echo "$0:ERROR: file $tmpdir/rpm exists, cannot override"
    exit 1
fi
echo "#!/bin/sh" >$tmpdir/rpm
echo "exec $RPM_BUILD_ROOT$prefix/lib/openpkg/rpm --rcfile $tmpdir/rpm.1 \"\$@\"" >>$tmpdir/rpm
chmod a+x $tmpdir/rpm

#   direct our own "rpm" tool to adjusted macro sets
sed <`SOURCE rpmrc` >$tmpdir/rpm.1 \
    -e "s;^\\(macrofiles:\\) .*;\\1 $tmpdir/rpm.2:$tmpdir/rpm.3;"

#   use an adjusted vendor macro set
sed <$RPM_BUILD_ROOT$prefix/lib/openpkg/macros >$tmpdir/rpm.2 \
    -e "s;$prefix;$RPM_BUILD_ROOT$prefix;g"

#   override the vendor macro set
sed <`SOURCE rpmmacros` >$tmpdir/rpm.3 \
    -e "s;@SUSR@;$susr;" \
    -e "s;@SGRP@;$sgrp;" \
    -e "s;@MUSR@;$musr;" \
    -e "s;@MGRP@;$mgrp;" \
    -e "s;@RUSR@;$rusr;" \
    -e "s;@RGRP@;$rgrp;" \
    -e "s;@NUSR@;$nusr;" \
    -e "s;@NGRP@;$ngrp;" \
    -e "s;@LOC@;$loc;" \
    -e "s;^\\(%l_root_install *\\)@l_prefix@;\\1 $prefix;" \
    -e "s;^\\(%l_root_rpm *\\)@l_prefix@;\\1 $RPM_BUILD_ROOT$prefix;" \
    -e "s;^\\(%_specdir *\\).*;\\1 `pwd`;" \
    -e "s;^\\(%_sourcedir *\\).*;\\1 $distdir;" \
    -e "s;^\\(%_builddir *\\).*;\\1 $tmpdir;" \
    -e "s;^\\(%_tmppath *\\).*;\\1 $tmpdir;" \
    -e "s;^\\(%_buildshell *\\).*;\\1 /bin/sh;" \
    -e "s;@l_build_path@;/bin:/sbin:/usr/bin:/usr/sbin;g" \
    -e "s;@l_build_ldlp@;/usr/lib;g" \
    -e "s;@l_build_ulim@;:;g"

#   use an own $HOME/.popt in order to make sure the "rpm"
#   tool is able to execute its sub-tools "rpm<x>".
V_rpm=`grep V_rpm $spec | head -1 | awk '{ printf("%s", $3); }'`
sed <$RPM_BUILD_ROOT$prefix/lib/openpkg/rpmpopt-${V_rpm} >$tmpdir/.popt \
    -e "s;^\\(rpm.*exec.*\\)\\(rpm[bdeukv]*\\);\\1$RPM_BUILD_ROOT$prefix/lib/openpkg/\\2;"

#   activate the .popt file
HOME=$tmpdir
export HOME

##
##   now initialize the RPM database under the temporary install location
##

echo "++ initializing RPM database"
$tmpdir/rpm --initdb

##
##   now turn over and re-iterate over the RPM spec, but this time
##   with the real RPM tool.
##

echo "++ re-iterating over RPM specification procedures"
OPENPKG_BOOT=1
export OPENPKG_BOOT
$tmpdir/rpm -bb $spec

##
##   and finally overwrite the installation again, but this time by
##   installing officially through the "rpm" tool. This way we achieve
##   that RPM is remembered as an RPM package in its own database. We
##   just have to make sure the package is relocated while installing.
##   For this we could use --prefix=$RPM_BUILD_ROOT$prefix, but this
##   would create an incorrect filelist for "rpm" in the database.
##   Instead we use the --justdb option which means "rpm" behaves as it
##   would install into the real location, but does not actually install
##   anything. But as a side-effect, the database is now correct.
##

echo "++ overwriting RPM installation by installing via RPM itself"
$tmpdir/rpm -Uvh --force --noscripts --notriggers --justdb --ignoresize \
    $RPM_BUILD_ROOT$prefix/RPM/PKG/openpkg-*.rpm

##  Puhhhh!!! what a tricky bootstrapping procedure. But now we are
##  mostly finished. All we finally have to do is to roll a bootstrap
##  tarball in addition to the binary RPM and save the stuff in a
##  permanent location.

v="$version-$release"
t="`$tmpdir/rpm --eval '%{_target}'`-$loc"

#   find a reasonable destination directory for packages
if [ -d ../PKG/BIN ]; then
   dstdir=../PKG/BIN
elif [ -d ../PKG ]; then
   dstdir=../PKG
elif [ -d ../../PKG/BIN ]; then
   dstdir=../../PKG/BIN
elif [ -d ../../PKG ]; then
   dstdir=../../PKG
else
   dstdir=..
fi

#   create Source-RPM file
echo "++ creating bootstrap source RPM file"
$tmpdir/rpm -bs --nodeps $spec
cp $RPM_BUILD_ROOT$prefix/RPM/PKG/openpkg-$v.src.rpm $dstdir/
rm -f $RPM_BUILD_ROOT$prefix/RPM/PKG/openpkg-$v.src.rpm

#   create Binary-RPM file
echo "++ creating bootstrap binary RPM file"
cp $RPM_BUILD_ROOT$prefix/RPM/PKG/openpkg-$v.$t.rpm $dstdir/
rm -f $RPM_BUILD_ROOT$prefix/RPM/PKG/openpkg-$v.$t.rpm

#   create Binary-Bootstrap file
echo "++ creating bootstrap binary shell script"
cat $spec | sed -e "/^%pre$/,/^%/ p" -e 'd' | sed -e '/^%/d' -e 's/^ 	//' >$tmpdir/rpm.pre
sed <`SOURCE aux.wrapbin.sh` \
    -e "s;@SUSR@;$susr;" -e "s;@SGRP@;$sgrp;" \
    -e "s;@MUSR@;$musr;" -e "s;@MGRP@;$mgrp;" \
    -e "s;@RUSR@;$rusr;" -e "s;@RGRP@;$rgrp;" \
    -e "s;@NUSR@;$nusr;" -e "s;@NGRP@;$ngrp;" \
    -e "s;@l_prefix@;$prefix;" -e "s;@TGZ@;openpkg-$v.$t.tar.Z;" \
    -e "/^@PRE@/r $tmpdir/rpm.pre" |\
    sed -e '/^@PRE@/d' >$dstdir/openpkg-$v.$t.sh
files=`cat $spec |\
       sed -e '1,/%files/d' -e '/%clean/,$d' |\
       grep -v '^ *$' | grep -v '%defattr' |\
       sed -e 's;%config *;;' -e 's;%dir *;;' -e 's;%{l_prefix}/;;' -e 's;^ *;;' -e "s;%{V_rpm};${V_rpm};"`
for dbfile in Basenames Conflictname Group Name Packages Providename \
    Requirename Triggername; do
    files="$files RPM/DB/$dbfile"
done
( cd $RPM_BUILD_ROOT$prefix;
  $RPM_BUILD_ROOT$prefix/lib/openpkg/tar --no-recursion -cf - $files) |\
compress | uuencode openpkg-$v.$t.tar.Z >>$dstdir/openpkg-$v.$t.sh

#   cleanup
echo "++ cleaning up"
rm -rf $RPM_BUILD_ROOT
rm -rf $tmpdir/$name-$version
rm -f $tmpdir/rpm $tmpdir/rpm.[123] $tmpdir/.popt $tmpdir/rpm.pre
rm -f $prolog

#   final hint about results
set +x
echo "++ resulting files (placed into $dstdir):"
(cd $dstdir; ls -l openpkg-$v.$t.sh openpkg-$v.$t.rpm openpkg-$v.src.rpm)

