#!/bin/sh
#
# Very basic tools necessary to start Maneage's default building.
#
# Copyright (C) 2020-2025 Mohammad Akhlaghi <mohammad@akhlaghi.org>
#
# This script is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This script 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.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this script.  If not, see <http://www.gnu.org/licenses/>.





# Script settings
# ---------------
# Stop the script if there are any errors.
set -e





# Input arguments.
bdir="$1"
ddir="$2"
downloader="$3"
user_backup_urls="$4"





# Basic directories/files
topdir="$(pwd)"
sdir="$bdir"/software
tardir="$sdir"/tarballs
instdir="$sdir"/installed
tmpblddir="$sdir"/build-tmp
confdir=reproduce/software/config
ibidir="$instdir"/version-info/proglib
downloadwrapper=reproduce/analysis/bash/download-multi-try.sh

# Derived directories
bindir="$instdir"/bin
urlfile="$confdir"/urls.conf
versionsfile="$confdir"/versions.conf
checksumsfile="$confdir"/checksums.conf
backupfile="$confdir"/servers-backup.conf




# Set the system to first look into our newly installed programs.
export PATH="$bindir:$PATH"





# Load the backup servers, but separate the first one.
backupservers=""
topbackupserver=""
maneage_backup_urls=$(awk '!/^#/{printf "%s ", $1}' $backupfile)
backupservers_all="$user_backup_urls $maneage_backup_urls"
for b in $backupservers_all; do
    if [ x$topbackupserver = x ]; then
        topbackupserver=$b
    else
        backupservers="$backupservers $b"
    fi
done





# Download the necessary tarball.
download_tarball() {
  # Basic definitions
  maneagetar="$tardir"/"$tarball"

  # See if the tarball already exists in Maneage.
  if [ -f "$maneagetar" ]; then
    just_a_place_holder=1
  else
    ucname="$tardir"/"$tarball.unchecked"

    # If the URL is empty, use the top backup server
    if [ x$w = x ]; then
        bservers="$backupservers"
        tarballurl="$topbackupserver"/"$tarball"
    else
        bservers="$backupservers_all"
        tarballurl="$url"/"$tarball"
    fi

    # See if it is in the input-software directory, if so, make a link, if
    # not copy it. The only issue is that the file in the input-software
    # directory may actually be a link itself. So to avoid complications
    # with many links, we'll use 'realpath' (if it exists) to parse the
    # link and link to an actual file.
    if [ -f "$ddir/$tarball" ]; then
      if type realpath > /dev/null 2> /dev/null; then
        ln -sf "$(realpath "$ddir/$tarball")" "$ucname"
      else
        cp "$ddir/$tarball" "$ucname"
      fi
    else
      $downloadwrapper "$downloader" nolock $tarballurl "$ucname" \
                       "$bservers"
    fi

    # Make sure this is the correct tarball.
    if type sha512sum > /dev/null 2> /dev/null; then
      checksum=$(sha512sum "$ucname" | awk '{print $1}')
      expectedchecksum=$(awk '/^'$progname'-checksum/{print $3}' \
                             "$checksumsfile")
      if [ x$checksum = x$expectedchecksum ]; then mv "$ucname" "$maneagetar"
      else
        echo "ERROR: Non-matching checksum: $tarball"
        echo "Checksum should be: $expectedchecksum"
        echo "Checksum is:        $checksum"
        exit 1
      fi;
    else mv "$ucname" "$maneagetar"
    fi
  fi

  # If the tarball is newer than the (possibly existing) program (the
  # version has changed), then delete the program. When the LaTeX name is
  # not given here, the software is re-built later (close to the end of
  # 'basic.mk') and the name is properly placed there.
  if [ -f "$ibidir/$progname" ]; then
      if [ "$maneagetar" -nt "$ibidir/$progname" ]; then
          rm "$ibidir/$progname"
      fi
  fi
}





# Build the program from the tarball. This function takes one argument
# which is the configure-time options.
build_program() {
  if ! [ -f "$ibidir/$progname" ]; then

    # Options
    configoptions=$1

    # Go into the temporary building directory.
    cd "$tmpblddir"
    unpackdir="$progname"-"$version"

    # Some implementations of 'tar' don't recognize Lzip, so we need to
    # manually call Lzip first, then call tar afterwards.
    csuffix=$(echo "$tarball" | sed -e's/\./ /g' | awk '{print $NF}')
    rm -rf "$unpackdir"
    if [ x$csuffix = xlz ]; then
      intarrm=1
      intar=$(echo "$tarball" | sed -e's/.lz//')
      lzip -c -d "$tardir/$tarball" > $intar
    else
      intarrm=0
      intar="$tardir"/"$tarball"
    fi

    # Unpack the tarball and go into it.
    tar xf "$intar"
    if [ x$intarrm = x1 ]; then rm "$intar"; fi
    cd "$unpackdir"

    # build the project, either with Make and either without it.
    if [ x$progname = xlzip ]; then
        ./configure --build --check --installdir="$instdir/bin" $configoptions
    else
        # All others accept the configure script.
        ./configure --prefix="$instdir" $configoptions

        # In Flock 0.4.0 there is a crash that can be fixed by simply
        # replacing '%1u' with '%ld' on GNU/Linux and '%d' on macOS. This
        # has been reported to flock maintainers:
        # https://github.com/discoteq/flock/issues/33
        if [ x$progname = xflock ]; then
            case $on_mac_os in
                yes) sed -e's/\%1u/\%d/'  src/flock.c > src/flock-new.c;;
                no)  sed -e's/\%1u/\%ld/' src/flock.c > src/flock-new.c;;
                *)   echo "pre-make-build.sh: '$on_mac_os' unrecognized value for on_mac_os";;
            esac
            mv src/flock-new.c src/flock.c
        fi

        # To build GNU Make, we don't want to assume the existance of a
        # Make program, so we use its 'build.sh' script and its own built
        # 'make' program to install itself.
        if [ x$progname = xmake ]; then
            /bin/sh build.sh
            ./make install
        else
            make V=1
            make install
        fi
    fi

    # Clean up the source directory and write the LaTeX name of the
    # software (if necessary: otherwise, just make an empty file).
    cd "$topdir"
    rm -rf "$tmpblddir/$unpackdir"
    if [ x"$progname_tex" = x ]; then
        echo "" > "$ibidir/$progname"
    else
        echo "$progname_tex $version" > "$ibidir/$progname"
    fi
  fi
}





# Lzip
# ----
#
# Lzip is a compression program that is the first built program in Maneage
# because the sources of all other programs (including other compression
# softwaer) are compressed. Lzip has the advantage that it is very small
# (without compression it is just ~400Kb). So we use its '.tar' file and
# won't rely on the host's compression tools at all.
progname="lzip"
progname_tex="" # Lzip re-built after GCC (empty string to avoid repetition)
url=$(awk '/^'$progname'-url/{print $3}' $urlfile)
version=$(awk '/^'$progname'-version/{print $3}' "$versionsfile")
tarball=$progname-$version.tar
download_tarball
build_program





# GNU Make
# --------
#
# The job orchestrator of Maneage is GNU Make. The
# '--disable-dependency-tracking' configure-time option is necessary so
# Make doesn't check for an existing 'make' implementation (recall that we
# aren't assuming any 'make' on the host).
#
# If GNU Guile is already present on the host system, Make will try to link
# with it, and this will cause dependency problems later. So we have
# distabled Guile. If a project needs the Guile extensions of Make, we need
# to add a build rule for Guile in Maneage, with a special Guile-enabled
# Make that has a different executable name (using the '--program-prefix='
# configure option) from the "default" make (which is this one!).
progname="make"
progname_tex="" # Make re-built after GCC (empty string to avoid repetition)
url=$(awk '/^'$progname'-url/{print $3}' $urlfile)
version=$(awk '/^'$progname'-version/{print $3}' $versionsfile)
tarball=$progname-$version.tar.lz
download_tarball
build_program "--disable-dependency-tracking --without-guile"





# Dash
# ----
#
# Dash is a shell (http://gondor.apana.org.au/~herbert/dash). Having it in
# this phase will allow us to have a fixed/identical shell for 'basic.mk'
# (which builds GNU Bash).
progname="dash"
progname_tex="Dash"
url=$(awk '/^'$progname'-url/{print $3}' $urlfile)
version=$(awk '/^'$progname'-version/{print $3}' $versionsfile)
tarball=$progname-$version.tar.lz
download_tarball
build_program

# If the 'sh' symbolic link isn't set yet, set it to point to Dash.
if [ -f $bindir/sh ]; then just_a_place_holder=1
else ln -sf $bindir/dash $bindir/sh;
fi





# Flock
# -----
#
# Flock (or file-lock) is necessary to serialize operations when
# necessary. GNU/Linux machines have it as part of their 'util-linux'
# programs. But to be consistent in non-GNU/Linux systems, we will be using
# our own build.
#
# The reason that 'flock' is built here is that generally the building of
# software is done in parallel, but we need it to serialize the download
# process of the software tarballs to avoid network complications when too
# many simultaneous download commands are called.
progname="flock"
progname_tex="Discoteq flock"
url=$(awk '/^'$progname'-url/{print $3}' $urlfile)
version=$(awk '/^'$progname'-version/{print $3}' $versionsfile)
tarball=$progname-$version.tar.lz
download_tarball
build_program





# Finish this script successfully
exit 0