#!/bin/bash
# Script that checks against build infrastructure mistakes in the examples.

# Copyright (C) 2018-2026 Free Software Foundation, Inc.
#
# This program 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 program 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 program.  If not, see <https://www.gnu.org/licenses/>.
#
# Written by Bruno Haible.

# func_init sample
# sets environment variables for building and running the given sample.
func_init ()
{
  case "$1" in
    hello-objc-gnustep) . /usr/share/GNUstep/Makefiles/GNUstep.sh ;;
  esac
}


# func_autogen sample
# adds generated build infrastructure files to the given sample.
func_autogen ()
{
  case "$1" in
    hello-objc-gnustep)
      (func_init "$1"; cd "$1" && ./autogen.sh)
      ;;
    *)
      (cd "$1" && ./autogen.sh)
      ;;
  esac
}

# func_autoclean sample
# removes generated build infrastructure files from the given sample.
func_autoclean ()
{
  case "$1" in
    hello-objc-gnustep)
      (func_init "$1"; cd "$1" && ./autoclean.sh)
      ;;
    *)
      (cd "$1" && ./autoclean.sh)
      ;;
  esac
}

# func_configure sample [builddir]
# runs configure for the given sample, optionally in a VPATH build.
func_configure ()
{
  case "$1" in
    hello-objc-gnustep) ;;
    *)
      if test -n "$2"; then
        (cd "$1"
         mkdir "$2"
         (cd "$2" && ../configure)
        )
      else
        (cd "$1" && ./configure)
      fi
      ;;
  esac
}

# func_distclean sample [builddir]
# undoes the effects of func_configure sample [builddir].
func_distclean ()
{
  case "$1" in
    hello-objc-gnustep) ;;
    *)
      if test -n "$2"; then
        (cd "$1/$2" && make distclean)
      else
        (cd "$1" && make distclean)
      fi
      ;;
  esac
}

# func_maintainerclean sample [builddir]
# also removes files that are expensive to rebuild.
func_maintainerclean ()
{
  case "$1" in
    hello-objc-gnustep)
      (func_init "$1"; cd "$1" && make distclean)
      ;;
    *)
      if test -n "$2"; then
        (cd "$1/$2" && make maintainer-clean)
      else
        (cd "$1" && make maintainer-clean)
      fi
      ;;
  esac
}


# func_check_autoclean sample
# checks whether the autoclean.sh script is complete.
func_check_autoclean ()
{
  sample="$1"
  rm -f "$sample.out"

  rm -rf "$sample.bak"
  cp -a "$sample" "$sample.bak"
  func_autogen "$sample"
  func_autoclean "$sample"
  LC_ALL=C diff -r -q "$sample.bak" "$sample" | sed -n -e 's/^Only in //p' | sed -e 's|: |/|' > "$sample.out"
  if ! test -s "$sample.out"; then
    rm -f "$sample.out"
  fi
  rm -rf "$sample.bak"

  if test -f "$sample.out"; then
    echo "*** func_check_autoclean $sample error: Leftover files:"
    cat "$sample.out"
    rm -f hello-*.out
    exit 1
  fi
}


# Known configure failures:
# hello-c-gnome2: error: Could not find the gnomeConf.sh file that is generated by gnome-libs install
# hello-c-gnome3: error: can't find gtk+-3.0 >= 3.10
# hello-c++-qt: error: cannot find correct Qt headers!
# hello-c++-kde: configure: error: Qt (>= Qt 3.1.0) (headers and libraries) not found. Please check your installation!
# hello-c++-gnome2: error: Could not find the gnomeConf.sh file that is generated by gnome-libs install
# hello-objc-gnome2: error: Could not find the gnomeConf.sh file that is generated by gnome-libs install
# hello-ycp: *** Essential program y2base not found

# func_check_distclean sample
# checks 'make distclean' directly after 'configure'.
func_check_distclean ()
{
  sample="$1"
  rm -f "$sample.log" "$sample.out"

  rm -rf "$sample.bak"
  func_autogen "$sample"
  cp -a "$sample" "$sample.bak"
  if func_configure "$sample" > "$sample.log" 2>&1; then
    rm -f "$sample.log"
    func_distclean "$sample"
    LC_ALL=C diff -r -q "$sample.bak" "$sample" | sed -n -e 's/^Only in //p' | sed -e 's|: |/|' > "$sample.out"
  fi
  func_autoclean "$sample"
  if ! test -s "$sample.out"; then
    rm -f "$sample.out"
  fi
  rm -rf "$sample.bak"

  if test -f "$sample.log"; then
    echo "*** func_check_distclean $sample error: 'configure' failures"
    echo "$sample.log"
    exit 1
  fi
  if test -f "$sample.out"; then
    echo "*** func_check_distclean $sample error: incomplete 'make distclean'"
    echo "$sample.out"
    exit 1
  fi
}


# Known make failures:
# hello-java-qtjambi: error: package com.trolltech.qt.core does not exist

# func_check_maintainerclean sample
# checks 'make distclean' after 'configure; make'.
func_check_maintainerclean ()
{
  sample="$1"
  rm -f "$sample.log" "$sample.out"

  rm -rf "$sample.bak"
  func_autogen "$sample"
  cp -a "$sample" "$sample.bak"
  if func_configure "$sample"; then
    if (func_init "$sample"; cd "$sample" && make) > "$sample.log" 2>&1; then
      rm -f "$sample.log"
    fi
  fi
  func_maintainerclean "$sample"
  # TODO: Remove .pot files workaround after next release.
  # TODO: Remove .po~ files workaround.
  LC_ALL=C diff -r -q "$sample.bak" "$sample" | sed -n -e 's/^Only in //p' | sed -e 's|: |/|' | grep "^${sample}/" | { if test -f "$sample"/po/Makevars || test "$sample" = hello-objc-gnustep; then grep -v '\.pot$'; else cat; fi; } | grep -v '\.po~$' > "$sample.out"
  func_autoclean "$sample"
  if ! test -s "$sample.out"; then
    rm -f "$sample.out"
  fi
  rm -rf "$sample.bak"

  if test -f "$sample.log"; then
    echo "*** func_check_maintainerclean $sample error: 'make' failures"
    echo "$sample.log"
    exit 1
  fi
  if test -f "$sample.out"; then
    echo "*** func_check_maintainerclean $sample error: incomplete 'make maintainer-clean'"
    echo "$sample.out"
    exit 1
  fi
}


# func_check_maintainerclean_vpath sample
# checks 'make distclean' after 'configure; make' with a VPATH build.
func_check_maintainerclean_vpath ()
{
  sample="$1"
  rm -f "$sample.log" "$sample.out"

  case "$sample" in
    hello-objc-gnustep) ;;
    *)
      rm -rf "$sample.bak"
      func_autogen "$sample"
      cp -a "$sample" "$sample.bak"
      if func_configure "$sample" build; then
        if (func_init "$sample"; cd "$sample"/build && make) > "$sample.log" 2>&1; then
          rm -f "$sample.log"
        fi
      fi
      func_maintainerclean "$sample" build
      # TODO: Remove .pot files workaround after next release.
      # TODO: Remove .po~ files workaround.
      find "$sample"/build -type f | LC_ALL=C sort | { if test -f "$sample"/po/Makevars; then grep -v '\.pot$'; else cat; fi; } | grep -v '\.po~$' > "$sample.out"
      rm -rf "$sample"/build
      func_autoclean "$sample"
      if ! test -s "$sample.out"; then
        rm -f "$sample.out"
      fi
      rm -rf "$sample.bak"
      ;;
  esac

  if test -f "$sample.log"; then
    echo "*** func_check_maintainerclean_vpath $sample error: 'make' failures"
    echo "$sample.log"
    exit 1
  fi
  if test -f "$sample.out"; then
    echo "*** func_check_maintainerclean_vpath $sample error: incomplete 'make maintainer-clean'"
    echo "$sample.out"
    exit 1
  fi
}


# func_check_dist sample
# checks 'make dist' after 'configure; make'.
func_check_dist ()
{
  sample="$1"
  rm -f "$sample.log" "$sample.out"

  case "$sample" in
    hello-objc-gnustep) ;;
    *)
      func_autogen "$sample"
      if func_configure "$sample"; then
        if (func_init "$sample"; cd "$sample" && make); then
          if (func_init "$sample"; cd "$sample" && make dist) > "$sample.log" 2>&1; then
            rm -f "$sample.log"
            (func_init "$sample"; cd "$sample" && make distclean)
            rm -f `find "$sample" -name '*~'` `find "$sample" -name '*.orig'`
            rm -rf "$sample/autom4te.cache"
            if test -f "$sample/$sample-0.tar.gz"; then
              (cd "$sample" && tar xfz "$sample-0.tar.gz")
              LC_ALL=C diff -r -q "$sample" "$sample/$sample-0" | grep -v "^Only in $sample: $sample-0\$" | grep -v "^Only in $sample: $sample-0.tar.gz\$" | grep -v "^Only in $sample: BUGS\$" | grep -v "^Only in hello-rust: target\$" > "$sample.out"
            else
              echo "$sample-0.tar.gz was not created" > "$sample.out"
            fi
          fi
          rm -rf "$sample/$sample-0"
          rm -f "$sample/$sample-0.tar.gz"
        fi
      fi
      func_configure "$sample"
      func_maintainerclean "$sample"
      func_autoclean "$sample"
      if ! test -s "$sample.out"; then
        rm -f "$sample.out"
      fi
      ;;
  esac

  if test -f "$sample.log"; then
    echo "*** func_check_dist $sample error: 'make dist' failures"
    echo "$sample.log"
    exit 1
  fi
  if test -f "$sample.out"; then
    echo "*** func_check_dist $sample error: tarball created by 'make dist' does not contain the expected files"
    echo "$sample.out"
    exit 1
  fi
}


# func_check_dist_vpath sample
# checks 'make dist' after 'configure; make' with a VPATH build
func_check_dist_vpath ()
{
  sample="$1"
  rm -f "$sample.log" "$sample.out"

  case "$sample" in
    hello-objc-gnustep) ;;
    *)
      func_autogen "$sample"
      if func_configure "$sample" build; then
        if (func_init "$sample"; cd "$sample"/build && make); then
          if (func_init "$sample"; cd "$sample"/build && make dist) > "$sample.log" 2>&1; then
            rm -f "$sample.log"
            (func_init "$sample"; cd "$sample"/build && make distclean)
            rm -f `find "$sample" -name '*~'` `find "$sample" -name '*.orig'`
            rm -rf "$sample/autom4te.cache"
            if test -f "$sample/build/$sample-0.tar.gz"; then
              (cd "$sample"/build && tar xfz "$sample-0.tar.gz")
              # TODO: Remove stamp-po workaround after next release.
              LC_ALL=C diff -r -q "$sample" "$sample/build/$sample-0" | grep -v "^Only in $sample: build\$" | grep -v "^Only in $sample: BUGS\$" | grep -v "^Only in hello-rust: target\$" | { if test -f "$sample"/po/Makevars; then grep -v "^Only in $sample/build/$sample-0/po: stamp-po\$"; else cat; fi; } > "$sample.out"
            else
              echo "$sample-0.tar.gz was not created" > "$sample.out"
            fi
          fi
          rm -rf "$sample/build/$sample-0"
          rm -f "$sample/build/$sample-0.tar.gz"
        fi
      fi
      rm -rf "$sample"/build
      func_autoclean "$sample"
      if ! test -s "$sample.out"; then
        rm -f "$sample.out"
      fi
      ;;
  esac

  if test -f "$sample.log"; then
    echo "*** func_check_dist_vpath $sample error: 'make dist' failures"
    echo "$sample.log"
    exit 1
  fi
  if test -f "$sample.out"; then
    echo "*** func_check_dist_vpath $sample error: tarball created by 'make dist' does not contain the expected files"
    echo "$sample.out"
    exit 1
  fi
}


# Base installation directory for all samples.
instdir=/tmp/gtexinst

# func_check_install sample
# checks 'make install' after 'configure; make'.
# You need to check afterwards whether the installed binaries work.
func_check_install ()
{
  sample="$1"
  rm -f "$sample.log"
  rm -rf "$instdir/$sample"

  case "$sample" in
    hello-objc-gnustep)
      # In this sample, you have to check the uninstalled binaries (see the INSTALL file).
      ;;
    *)
      func_autogen "$sample"
      if (cd "$sample" && ./configure --prefix="$instdir/$sample"); then
        if (func_init "$sample"; cd "$sample" && make); then
          if (func_init "$sample"; cd "$sample" && make install) > "$sample.log" 2>&1; then
            rm -f "$sample.log"
          fi
        fi
      fi
      func_maintainerclean "$sample"
      func_autoclean "$sample"
      ;;
  esac

  if test -f "$sample.log"; then
    echo "*** func_check_install $sample error: 'make install' failures"
    echo "$sample.log"
    exit 1
  fi
}


# func_check_uninstall sample
# checks 'make uninstall' after 'configure; make; make install'.
func_check_uninstall ()
{
  sample="$1"
  rm -f "$sample.log" "$sample.out"
  rm -rf "$instdir/$sample"

  case "$sample" in
    hello-objc-gnustep)
      # In this sample, you have to check the uninstalled binaries (see the INSTALL file).
      ;;
    *)
      func_autogen "$sample"
      if (cd "$sample" && ./configure --prefix="$instdir/$sample"); then
        if (func_init "$sample"; cd "$sample" && make); then
          if (func_init "$sample"; cd "$sample" && make install); then
            if (func_init "$sample"; cd "$sample" && make uninstall) > "$sample.log" 2>&1; then
              rm -f "$sample.log"
              (cd "$instdir" && find "$sample" -type f | LC_ALL=C sort) > "$sample.out"
            fi
          fi
        fi
      fi
      func_maintainerclean "$sample"
      func_autoclean "$sample"
      if ! test -s "$sample.out"; then
        rm -f "$sample.out"
      fi
      ;;
  esac

  if test -f "$sample.log"; then
    echo "*** func_check_uninstall $sample error: 'make uninstall' failures"
    echo "$sample.log"
    exit 1
  fi
  if test -f "$sample.out"; then
    echo "*** func_check_uninstall $sample error: left-over files"
    echo "$sample.out"
    exit 1
  fi
}


# func_check_distcheck sample
# checks 'make distcheck' after 'configure; make'.
func_check_distcheck ()
{
  sample="$1"
  rm -f "$sample.log"

  case "$sample" in
    hello-objc-gnustep) ;;
    *)
      func_autogen "$sample"
      if func_configure "$sample"; then
        if (func_init "$sample"; cd "$sample" && make); then
          if (func_init "$sample"; cd "$sample" && make distcheck) > "$sample.log" 2>&1; then
            rm -f "$sample.log"
          fi
          if test -d "$sample/$sample-0"; then chmod -R u+w "$sample/$sample-0"; fi
          rm -rf "$sample/$sample-0"
          rm -f "$sample/$sample-0.tar.gz"
        fi
      fi
      func_maintainerclean "$sample"
      func_autoclean "$sample"
      if ! test -s "$sample.out"; then
        rm -f "$sample.out"
      fi
      ;;
  esac

  if test -f "$sample.log"; then
    echo "*** func_check_distcheck $sample error: 'make distcheck' failures"
    echo "$sample.log"
    exit 1
  fi
}


# A check function for a single sample, when there are no problems.
func_check ()
{
  func_check_autoclean "$1"
  func_check_distclean "$1"
  func_check_maintainerclean "$1"
  func_check_maintainerclean_vpath "$1"
  func_check_dist "$1"
  func_check_dist_vpath "$1"
  func_check_install "$1"
  func_check_uninstall "$1"
  func_check_distcheck "$1"
}

# A check function for each sample.

func_check__hello_c ()
{
  func_check hello-c
}

func_check__hello_c_gnome2 ()
{
  func_check_autoclean hello-c-gnome2
 #func_check_distclean hello-c-gnome2
 #func_check_maintainerclean hello-c-gnome2
 #func_check_maintainerclean_vpath hello-c-gnome2
 #func_check_dist hello-c-gnome2
 #func_check_dist_vpath hello-c-gnome2
 #func_check_install hello-c-gnome2
 #func_check_uninstall hello-c-gnome2
 #func_check_distcheck hello-c-gnome2
}

func_check__hello_c_gnome3 ()
{
  func_check_autoclean hello-c-gnome3
  func_check_distclean hello-c-gnome3
  func_check_maintainerclean hello-c-gnome3
  func_check_maintainerclean_vpath hello-c-gnome3
  func_check_dist hello-c-gnome3
 # This sample has some MAINTAINERCLEANFILES that are distributed.
 #func_check_dist_vpath hello-c-gnome3
  func_check_install hello-c-gnome3
  func_check_uninstall hello-c-gnome3
  func_check_distcheck hello-c-gnome3
}

func_check__hello_c_http ()
{
  func_check hello-c-http
}

func_check__hello_cxx ()
{
  func_check hello-c++
}

func_check__hello_cxx20 ()
{
  func_check hello-c++20
}

func_check__hello_cxx_qt ()
{
  func_check_autoclean hello-c++-qt
 #func_check_distclean hello-c++-qt
 #func_check_maintainerclean hello-c++-qt
 #func_check_maintainerclean_vpath hello-c++-qt
 #func_check_dist hello-c++-qt
 #func_check_dist_vpath hello-c++-qt
 #func_check_install hello-c++-qt
 #func_check_uninstall hello-c++-qt
 #func_check_distcheck hello-c++-qt
}

func_check__hello_cxx_kde ()
{
  func_check_autoclean hello-c++-kde
 #func_check_distclean hello-c++-kde
 #func_check_maintainerclean hello-c++-kde
 #func_check_maintainerclean_vpath hello-c++-kde
 #func_check_dist hello-c++-kde
 #func_check_dist_vpath hello-c++-kde
 #func_check_install hello-c++-kde
 #func_check_uninstall hello-c++-kde
 #func_check_distcheck hello-c++-kde
}

func_check__hello_cxx_gnome2 ()
{
  func_check_autoclean hello-c++-gnome2
 #func_check_distclean hello-c++-gnome2
 #func_check_maintainerclean hello-c++-gnome2
 #func_check_maintainerclean_vpath hello-c++-gnome2
 #func_check_dist hello-c++-gnome2
 #func_check_dist_vpath hello-c++-gnome2
 #func_check_install hello-c++-gnome2
 #func_check_uninstall hello-c++-gnome2
 #func_check_distcheck hello-c++-gnome2
}

func_check__hello_cxx_gnome3 ()
{
  func_check_autoclean hello-c++-gnome3
  func_check_distclean hello-c++-gnome3
  func_check_maintainerclean hello-c++-gnome3
  func_check_maintainerclean_vpath hello-c++-gnome3
  func_check_dist hello-c++-gnome3
 # This sample has some MAINTAINERCLEANFILES that are distributed.
 #func_check_dist_vpath hello-c++-gnome3
  func_check_install hello-c++-gnome3
  func_check_uninstall hello-c++-gnome3
  func_check_distcheck hello-c++-gnome3
}

func_check__hello_cxx_wxwidgets ()
{
  func_check hello-c++-wxwidgets
}

func_check__hello_objc ()
{
  func_check hello-objc
}

func_check__hello_objc_gnustep ()
{
  func_check hello-objc-gnustep
}

func_check__hello_objc_gnome2 ()
{
  func_check_autoclean hello-objc-gnome2
 #func_check_distclean hello-objc-gnome2
 #func_check_maintainerclean hello-objc-gnome2
 #func_check_maintainerclean_vpath hello-objc-gnome2
 #func_check_dist hello-objc-gnome2
 #func_check_dist_vpath hello-objc-gnome2
 #func_check_install hello-objc-gnome2
 #func_check_uninstall hello-objc-gnome2
 #func_check_distcheck hello-objc-gnome2
}

func_check__hello_python ()
{
  func_check hello-python
}

func_check__hello_java ()
{
  func_check hello-java
}

func_check__hello_java_awt ()
{
  func_check hello-java-awt
}

func_check__hello_java_swing ()
{
  func_check hello-java-swing
}

func_check__hello_java_qtjambi ()
{
  func_check_autoclean hello-java-qtjambi
  func_check_distclean hello-java-qtjambi
 #func_check_maintainerclean hello-java-qtjambi
 #func_check_maintainerclean_vpath hello-java-qtjambi
 #func_check_dist hello-java-qtjambi
 #func_check_dist_vpath hello-java-qtjambi
 #func_check_install hello-java-qtjambi
 #func_check_uninstall hello-java-qtjambi
 #func_check_distcheck hello-java-qtjambi
}

func_check__hello_csharp ()
{
  func_check hello-csharp
}

func_check__hello_csharp_forms ()
{
  func_check hello-csharp-forms
}

func_check__hello_guile ()
{
  func_check hello-guile
}

func_check__hello_clisp ()
{
  func_check hello-clisp
}

func_check__hello_librep ()
{
  func_check hello-librep
}

func_check__hello_rust ()
{
  func_check hello-rust
}

func_check__hello_go ()
{
  func_check hello-go
}

func_check__hello_go_http ()
{
  func_check hello-go-http
}

func_check__hello_ruby ()
{
  func_check hello-ruby
}

func_check__hello_sh ()
{
  func_check hello-sh
}

func_check__hello_gawk ()
{
  func_check hello-gawk
}

func_check__hello_pascal ()
{
  func_check hello-pascal
}

func_check__hello_modula2 ()
{
  func_check hello-modula2
}

func_check__hello_d ()
{
  func_check hello-d
}

func_check__hello_ocaml ()
{
  func_check hello-ocaml
}

func_check__hello_smalltalk ()
{
  func_check hello-smalltalk
}

func_check__hello_tcl ()
{
  func_check hello-tcl
}

func_check__hello_tcl_tk ()
{
  func_check hello-tcl-tk
}

func_check__hello_perl ()
{
  func_check hello-perl
}

func_check__hello_php ()
{
  func_check hello-php
}

func_check__hello_ycp ()
{
  func_check_autoclean hello-ycp
 #func_check_distclean hello-ycp
 #func_check_maintainerclean hello-ycp
 #func_check_maintainerclean_vpath hello-ycp
 #func_check_dist hello-ycp
 #func_check_dist_vpath hello-ycp
 #func_check_install hello-ycp
 #func_check_uninstall hello-ycp
 #func_check_distcheck hello-ycp
}


# Top-level code.

# For checking a single example:
#func_check__hello_...
#exit 0

func_check__hello_c               #   47 s
func_check__hello_c_gnome2
func_check__hello_c_gnome3        #   48 s
func_check__hello_c_http          #   48 s
func_check__hello_cxx             #   50 s
func_check__hello_cxx20           #   94 s  # requires GCC 14 or newer
func_check__hello_cxx_qt
func_check__hello_cxx_kde
func_check__hello_cxx_gnome2
func_check__hello_cxx_gnome3      #   58 s
func_check__hello_cxx_wxwidgets   #   62 s
func_check__hello_objc            #   48 s
func_check__hello_objc_gnustep    #    3 s
func_check__hello_objc_gnome2
func_check__hello_python          #   34 s
func_check__hello_java            #   96 s
func_check__hello_java_awt        #  102 s
func_check__hello_java_swing      #   99 s
func_check__hello_java_qtjambi
func_check__hello_csharp          #  133 s
func_check__hello_csharp_forms    #  136 s
func_check__hello_guile           #   33 s
func_check__hello_clisp           #   32 s
func_check__hello_librep          #   32 s
func_check__hello_rust            #  385 s
func_check__hello_go              #   57 s  # requires GCC 14 or older, does not work with GCC 15.1
func_check__hello_go_http         #   41 s  # likewise
func_check__hello_ruby            #   34 s
func_check__hello_sh              #   34 s
func_check__hello_gawk            #   32 s
func_check__hello_pascal          #   33 s
func_check__hello_modula2         #   46 s  # requires GCC 15 or newer
func_check__hello_d               #   70 s
func_check__hello_ocaml           #   33 s  # requires "eval $(opam env)"
func_check__hello_smalltalk       #   32 s
func_check__hello_tcl             #   36 s
func_check__hello_tcl_tk          #   36 s
func_check__hello_perl            #   32 s
func_check__hello_php             #   32 s
func_check__hello_ycp
