#!/usr/bin/env python
#
# Copyright (C) 2005-2010 ABINIT Group (Yann Pouillon)
#
# This file is part of the ABINIT software package. For license information,
# please see the COPYING file in the top-level directory of the ABINIT source
# distribution.
#

# NOTE: this scripts changes the current directory to tests/.

from ConfigParser import ConfigParser
from time import gmtime,strftime

import commands
import os
import re
import sys

class MyConfigParser(ConfigParser):

  def optionxform(self,option):
    return str(option)

# ---------------------------------------------------------------------------- #

#
# Subroutines
#

# Makefile header
def makefile_header(name,stamp):

  return """#
# Makefile for ABINIT                                      -*- Automake -*-
#

# Generated by %s on %s

#
# IMPORTANT NOTE
#
# Any manual change to this file will systematically be overwritten.
# Please modify the %s script or its config file instead.
#

#
# If you want to execute a range of tests instead of a whole series, you
# may use the keywords "start", "stop" and "dirname" along with make, e.g.:
#
#    make v1 start=100 stop=104 dirname=root_name_for_the_test_directory
#
# To execute only one test, just omit either start or stop.
# By default, the dirname is the hostname
#
# Default host name for test output directories
dirname = `hostname`

# Main test scripts
run_basic_tests = timeout="$(nightly_timeout)" $(PERL) \\
  $(top_srcdir)/tests/Scripts/run-basic-tests.pl
run_standard_tests = timeout="$(nightly_timeout)" $(BOURNE_SHELL) \\
  $(top_srcdir)/tests/Scripts/wrap-standard-tests.sh
run_parallel_tests = $(BOURNE_SHELL) \\
  $(top_srcdir)/tests/Scripts/wrap-parallel-tests.sh

# External libraries
run_netcdf_tests = $(BOURNE_SHELL) \\
  $(top_srcdir)/tests/Scripts/run-netcdf-tests.sh

# Utilities for nightly builds
if DO_BUILD_NIGHTLY
  SUBDIRS = Nightly
endif

# Display help by default
all-local: help

if DO_BUILD_NIGHTLY
nightly-stamp:
	cd Nightly && $(MAKE) @SET_MAKE@
	touch nightly-stamp
else
nightly-stamp:
	@echo "Nightly builds are disabled"
	touch nightly-stamp
endif

help:
	@cat $(top_srcdir)/doc/help_make/help_make_tests

""" % (name,stamp,name)

# File lists
def file_list(name,dir):
  tmp = "# Files from %s\n%s =" % (dir,name)
  olddir = re.compile(",.*")
  tmpdir = re.compile("tmp-*")
  vimswp = re.compile("\..*\.swp")

  # Find files to install
  for root,dirs,files in os.walk(dir):
    # Clean-up lists
    if ( "Makefile.am" in files ):
      files.remove("Makefile.am")
    if ( "Makefile.in" in files ):
      files.remove("Makefile.in")
    if ( "Makefile" in files ):
      files.remove("Makefile")
    if ( "tests.env.in" in files ):
      files.remove("tests.env.in")
    if ( "tests.env" in files ):
      files.remove("tests.env")
    if ( "tests-install.env.in" in files ):
      files.remove("tests-install.env.in")
    if ( "tests-install.env" in files ):
      files.remove("tests-install.env")

    # Sort lists
    dirs.sort()
    files.sort()

    # We don't want to distribute nor install temporary directories
    for sub in dirs:
      if olddir.match(sub):
        dirs.remove(sub)
      if tmpdir.match(sub):
        dirs.remove(sub)

    # Add data files
    for dat in files:
      if ( not vimswp.match(dat) ):
        tmp += " \\\n\t%s" % (os.path.join(root,dat))

  tmp += "\n\n"

  return tmp



# Built-in tests : this lacks the  if DO_BUILD_BIGDFT or similar expressions
def built_in_tests():

  return """# Built-in tests
#tests_in tests: $(psps_for_tests) $(tests_in_inps) nightly-stamp
#	@if test ! -e built-in; then $(MKDIR_P) built-in; fi
#	@for bit in in_1 in_2 in_3 in_bigdft in_etsf_io in_libxc in_wannier90 ; do \
#	   echo "Running built-in test $${bit}"; \
#	   $(run_basic_tests) built-in $${bit} $(abinit_srcdir); \
#	 done

"""



# External library tests
def external_tests(lib,test_alias):

  return """# External library tests: %s
if DO_TEST_%s
tests_%s %s: $(psps_for_tests) $(tests_%s_inps) nightly-stamp
	@if test ! -e %s; then $(MKDIR_P) %s; fi
	@$(run_%s_tests)
endif

""" % (lib,lib.upper(),lib,test_alias,lib,lib,lib,lib)



# Optional library tests
def optional_tests(lib,test_alias):

  return """# Optional library tests: %s
if DO_TEST_%s
tests_%s %s: $(psps_for_tests) $(tests_%s_inps) nightly-stamp
	@if test ! -e %s; then $(MKDIR_P) %s; fi
	$(run_standard_tests) $(dirname) %s $(start) $(stop)
endif

""" % (lib,lib.upper(),lib,test_alias,lib,lib,lib,lib)



# Test targets
def tests_target(dir,test_alias):

  return """# The "%s" series
tests_%s %s: $(tests_%s_inps) $(psps_for_tests) nightly-stamp
	@if test ! -e %s; then $(MKDIR_P) %s; fi
	rm -rf %s/*/*SCR
	$(run_standard_tests) $(dirname) %s $(start) $(stop)

""" % (dir,dir,test_alias,dir,dir,dir,dir,dir)



# Parallel tests
def parallel_tests(dir,test_alias):

  if ( dir == "paral" ):
    paral_host="$(paral_host)"
    paral_mode="$(paral_mode)"
    start_stop="$(start) $(stop)"
  elif ( dir == "mpiio" ):
    paral_host="$(paral_host)"
    paral_mode="mpiio"
    start_stop="$(start) $(stop)"
  else:
    paral_host="$(paral_host)"
    paral_mode=dir
    start_stop=""

  return """# Parallel series %s
tests_%s %s: $(tests_%s_inps) $(psps_for_tests) nightly-stamp
	@if test ! -e %s; then $(MKDIR_P) %s; fi
	$(run_parallel_tests) %s %s %s

""" % (dir,dir,test_alias,dir,dir,dir,paral_host,paral_mode,start_stop)



# ---------------------------------------------------------------------------- #

#
# Main program
#

# Initial setup
my_name    = "make-makefiles-tests"
my_configs = ["config/specs/tests.conf"]
my_output  = "Makefile.am"

# Check if we are in the top of the ABINIT source tree
if ( not os.path.exists("configure.ac") or
     not os.path.exists("src/98_main/abinit.F90") ):
  print "%s: You must be in the top of the ABINIT source tree." % my_name
  print "%s: Aborting now." % my_name
  sys.exit(1)

# Read config file(s)
cnf = MyConfigParser()
for cnf_file in my_configs:
  if ( not os.path.exists(cnf_file) ):
    print "%s: Could not find config file (%s)." % (my_name,cnf_file)
    print "%s: Aborting now." % my_name
    sys.exit(2)

# What time is it?
now = strftime("%Y/%m/%d %H:%M:%S +0000",gmtime())

# Init
cnf.read(my_configs[0])
abinit_tests = cnf.sections()
abinit_tests.sort()

# Go to the tests directory first
os.chdir("tests")

# Start to write tests/Makefile.am
mf = file(my_output,"w")
mf.write(makefile_header(my_name,now))

# Prepare EXTRA_DIST target
ins = "nobase_dist_pkgdata_DATA = \\\n\t$(tests_scripts)" + \
  " \\\n\t$(psps_for_tests) \\\n\t$(tests_in_inps)"

# Prepare clean-local target
cln = "clean-local:\n\trm -f nightly-stamp\n\trm -rf built-in/tmp-*\n"

# Write file lists and targets
mf.write(file_list("tests_scripts","Scripts"))
mf.write(file_list("psps_for_tests","Psps_for_tests"))
mf.write(file_list("tests_in_inps","built-in"))
mf.write(built_in_tests())

for dir in abinit_tests:

  # Init
  aliases = cnf.get(dir,"aliases")
  dir_ext = cnf.get(dir,"external")
  dir_mpi = cnf.get(dir,"mpi")
  dir_opt = cnf.get(dir,"optional")

  # Append info
  ins += " \\\n\t$(tests_%s_inps)" % (dir)
  cln += "\trm -rf %s/tmp-*\n" % (dir)

  # Write file list and targets
  mf.write(file_list("tests_%s_inps" % (dir),dir))
  if ( dir_mpi == "yes" ):
    mf.write(parallel_tests(dir,aliases))
  else:
    if ( dir_ext == "yes" ):
      mf.write(external_tests(dir,aliases))
    elif ( dir_opt == "yes" ):
      mf.write(optional_tests(dir,aliases))
    else:
      mf.write(tests_target(dir,aliases))

# Write *DATA and clean-local
ins += """

install-data-local: tests-install.env Makefile
	$(INSTALL) -d -m 755 $(DESTDIR)$(pkgdatadir)
	$(SED) -e s,@pkgdatadir@,$(pkgdatadir),g \\
	  < tests-install.env \\
	  > $(DESTDIR)$(pkgdatadir)/tests.env

uninstall-local:
	/bin/rm -f $(DESTDIR)$(pkgdatadir)/tests.env

"""
cln += "\n"
mf.write(ins+cln)

# Go back to the top directory
os.chdir("..")

# Look for additional information
add = "config/makefiles/tests.am"
if ( os.path.exists(add) ):
  mf.write(file(add,"r").read())

mf.close()
