[Ncep.list.nems.announce] nems r92559: NEMS updates:
Samuel.Trahan at noaa.gov
Samuel.Trahan at noaa.gov
Tue May 9 19:43:05 UTC 2017
1. Minor changes required for
NEMSfv3gf...
Message-ID: <59121bc9.PqNQr61r4zaqv31u%Samuel.Trahan at noaa.gov>
User-Agent: Heirloom mailx 12.4 7/29/08
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="=_59121bc9.mxbY+RCbbOnLoVlWRkmLNZdlDm0kOUig//vPB7KM/+3cESLJ"
This is a multi-part message in MIME format.
--=_59121bc9.mxbY+RCbbOnLoVlWRkmLNZdlDm0kOUig//vPB7KM/+3cESLJ
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
Friendly NEMS developers,
This is an automated email about a NEMS commit.
Project: nems
URL: https://svnemc.ncep.noaa.gov/projects/nems/trunk
Revision: 92559
Author: samuel.trahan at noaa.gov
Date: 2017-05-09T19:40:36.593606Z
Message:
NEMS updates:
1. Minor changes required for NEMSfv3gfs support for jet.
Specifically:
1a. The compset runner can auto-detect a Jet project
with available CPU hours.
1b. It refuses to auto-detect a Jet scrub area. Jet has no concept
of "scrub areas." The script now gives instructions for how to
specify a scrub area if the user does not do so.
2. Allow NEMS/doc to be built without an application-level doc
3. Replace tests/rt.sh and NEMSCompsetRun with simple wrappers around
tests/rtgen. The tests/rtgen now understands both calling
conventions.
4. Safeguards against using the wrong produtil
5. Capability of resuming an aborted workflow in NEMSCompsetRun by
using the new --resume argument, instead of the two step process
required before.
6. Point to the top of produtil
_M .
_M tests
M tests/rtgen
M tests/rt.sh
M doc/Makefile
_M src
See attached file for full differences.
First 4000 bytes of differences:
Index: checkout/tests/rtgen
===================================================================
--- checkout/tests/rtgen (revision 90943)
+++ checkout/tests/rtgen (revision 92559)
@@ -1,5 +1,7 @@
#! /usr/bin/env python
+import fileinput
+import glob
import os
import sys
import re
@@ -31,7 +33,7 @@
help=NO
sleep_time=300
zero_exit=NO
-qoutq_more=''
+qoutql_more=''
for arg in "$@" ; do
case "$arg" in
-v|--verbose) verbose=$(( verbose + 1 )) ;;
@@ -39,7 +41,7 @@
--loop) loop=YES ;;
--help) help=YES ;;
--zero-exit) zero_exit=YES ;;
- -n) qoutq_more='-n' ;;
+ -n) qoutql_more='-n' ;;
*)
bad="$arg: invalid argument $bad"
esac
@@ -145,13 +147,13 @@
log "workflow is still running and no jobs have failed."
fi
fi
- if [[ "$have_qoutq" == YES ]] ; then
- job_count=$( qoutq -UL .queue_state $qoutq_more -Cd rtgen.$UNIQUE_ID | wc -l )
+ if [[ "$have_qoutql" == YES ]] ; then
+ job_count=$( qoutql -UL .queue_state $qoutql_more -Cd rtgen.$UNIQUE_ID | wc -l )
if [[ "$verbose" -gt 0 ]] ; then
verbose "sleep 2"
sleep 2
verbose "get queue information"
- qoutq -UL .queue_state $qoutq_more -Cd rtgen.$UNIQUE_ID
+ qoutql -UL .queue_state $qoutql_more -Cd rtgen.$UNIQUE_ID
fi
if [[ "$unchange" -gt 2 && "$job_count" < 1 && "$lostdead" -gt 0 ]] ; then
log "Jobs have FAILED and no jobs are running or submitted."
@@ -173,28 +175,37 @@
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Attempt to get the produtil package:
try:
+ import produtil.testing
import produtil.setup
except ImportError as ie:
altpath=os.path.join(os.path.dirname(os.path.realpath(__file__)),'produtil/ush')
if not os.path.isdir(altpath):
- fail('%s is missing and produtil is not in PYTHONPATH. Is your produtil external missing?'%(altpath,))
- sys.path.append(altpath)
- import produtil.setup
+ fail('%s is missing and a valid produtil is not in PYTHONPATH. Is your produtil external missing?'%(altpath,))
+ sys.path.append(altpath)
+ try:
+ import produtil.testing
+ import produtil.setup
+ except ImportError as ie2:
+ if not os.path.isdir(altpath):
+ fail('%s is missing and a valid produtil is not in PYTHONPATH. Is your produtil external missing?'%(altpath,))
-import produtil.run, produtil.cluster
+import produtil.run, produtil.cluster, produtil.fileop
from produtil.log import jlogger
-from produtil.run import runstr, ExitStatusException, checkrun, batchexe
+from produtil.run import runstr, ExitStatusException, checkrun, batchexe, run
from produtil.testing.testgen import TestGen
from produtil.testing.utilities import BASELINE, EXECUTION, bashify_string
from produtil.testing.rocoto import RocotoRunner
from produtil.testing.setarith import ArithKeyError
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Utility routines:
+########################################################################
-TOP_OF_USAGE_MESSAGE='''Syntax: rtgen [options] [subset]
+# Usage messages
+##@var RTGEN_TOP_OF_USAGE_MESSAGE
+# Text placed at the top of both the short and full rtgen usage messages
+RTGEN_TOP_OF_USAGE_MESSAGE='''Syntax: rtgen [options] [subset]
+
Generates an NCEP three-tier workflow structure to run the specified
regression tests or compsets. The user must then run some scripts
inside that directory to execute the tests and report the results.
@@ -201,11 +212,22 @@
If no subset is requested, all known tests are run.
'''
-SHORT_USAGE_MESSAGE=TOP_OF_USAGE_MESSAGE+'''
+##@var RTGEN_USAGE_MESSAGE
+# Text of rtgen's short usage message
+#
+# This text is sent to stderr by the rtgen_usage() function. It tells
+# the user the purpose of the program, but does not go into details about
+# the calling conventions.
+RTGEN_SHORT_USAGE_MESSAGE=RTGEN_TOP_OF_USAGE_MESSAGE+'''
Run with
... see attachment for the rest ...
--=_59121bc9.mxbY+RCbbOnLoVlWRkmLNZdlDm0kOUig//vPB7KM/+3cESLJ
Content-Type: text/plain;
charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="92559.diff"
Index: checkout/tests/rtgen
===================================================================
--- checkout/tests/rtgen (revision 90943)
+++ checkout/tests/rtgen (revision 92559)
@@ -1,5 +1,7 @@
#! /usr/bin/env python
+import fileinput
+import glob
import os
import sys
import re
@@ -31,7 +33,7 @@
help=NO
sleep_time=300
zero_exit=NO
-qoutq_more=''
+qoutql_more=''
for arg in "$@" ; do
case "$arg" in
-v|--verbose) verbose=$(( verbose + 1 )) ;;
@@ -39,7 +41,7 @@
--loop) loop=YES ;;
--help) help=YES ;;
--zero-exit) zero_exit=YES ;;
- -n) qoutq_more='-n' ;;
+ -n) qoutql_more='-n' ;;
*)
bad="$arg: invalid argument $bad"
esac
@@ -145,13 +147,13 @@
log "workflow is still running and no jobs have failed."
fi
fi
- if [[ "$have_qoutq" == YES ]] ; then
- job_count=$( qoutq -UL .queue_state $qoutq_more -Cd rtgen.$UNIQUE_ID | wc -l )
+ if [[ "$have_qoutql" == YES ]] ; then
+ job_count=$( qoutql -UL .queue_state $qoutql_more -Cd rtgen.$UNIQUE_ID | wc -l )
if [[ "$verbose" -gt 0 ]] ; then
verbose "sleep 2"
sleep 2
verbose "get queue information"
- qoutq -UL .queue_state $qoutq_more -Cd rtgen.$UNIQUE_ID
+ qoutql -UL .queue_state $qoutql_more -Cd rtgen.$UNIQUE_ID
fi
if [[ "$unchange" -gt 2 && "$job_count" < 1 && "$lostdead" -gt 0 ]] ; then
log "Jobs have FAILED and no jobs are running or submitted."
@@ -173,28 +175,37 @@
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Attempt to get the produtil package:
try:
+ import produtil.testing
import produtil.setup
except ImportError as ie:
altpath=os.path.join(os.path.dirname(os.path.realpath(__file__)),'produtil/ush')
if not os.path.isdir(altpath):
- fail('%s is missing and produtil is not in PYTHONPATH. Is your produtil external missing?'%(altpath,))
- sys.path.append(altpath)
- import produtil.setup
+ fail('%s is missing and a valid produtil is not in PYTHONPATH. Is your produtil external missing?'%(altpath,))
+ sys.path.append(altpath)
+ try:
+ import produtil.testing
+ import produtil.setup
+ except ImportError as ie2:
+ if not os.path.isdir(altpath):
+ fail('%s is missing and a valid produtil is not in PYTHONPATH. Is your produtil external missing?'%(altpath,))
-import produtil.run, produtil.cluster
+import produtil.run, produtil.cluster, produtil.fileop
from produtil.log import jlogger
-from produtil.run import runstr, ExitStatusException, checkrun, batchexe
+from produtil.run import runstr, ExitStatusException, checkrun, batchexe, run
from produtil.testing.testgen import TestGen
from produtil.testing.utilities import BASELINE, EXECUTION, bashify_string
from produtil.testing.rocoto import RocotoRunner
from produtil.testing.setarith import ArithKeyError
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Utility routines:
+########################################################################
-TOP_OF_USAGE_MESSAGE='''Syntax: rtgen [options] [subset]
+# Usage messages
+##@var RTGEN_TOP_OF_USAGE_MESSAGE
+# Text placed at the top of both the short and full rtgen usage messages
+RTGEN_TOP_OF_USAGE_MESSAGE='''Syntax: rtgen [options] [subset]
+
Generates an NCEP three-tier workflow structure to run the specified
regression tests or compsets. The user must then run some scripts
inside that directory to execute the tests and report the results.
@@ -201,11 +212,22 @@
If no subset is requested, all known tests are run.
'''
-SHORT_USAGE_MESSAGE=TOP_OF_USAGE_MESSAGE+'''
+##@var RTGEN_USAGE_MESSAGE
+# Text of rtgen's short usage message
+#
+# This text is sent to stderr by the rtgen_usage() function. It tells
+# the user the purpose of the program, but does not go into details about
+# the calling conventions.
+RTGEN_SHORT_USAGE_MESSAGE=RTGEN_TOP_OF_USAGE_MESSAGE+'''
Run with -h for full instructions.
'''
-FULL_USAGE_MESSAGE=TOP_OF_USAGE_MESSAGE+'''
+##@var RTGEN_USAGE_MESSAGE
+# Text of rtgen's full usage message
+#
+# This text is sent to stderr by the rtgen_full_usage() function. It
+# lists all calling convention information for the rtgen program.
+RTGEN_FULL_USAGE_MESSAGE=RTGEN_TOP_OF_USAGE_MESSAGE+'''
--SUBSETS--
{gfs_slg,nmm_cntrl} -- run gfs_slg and nmm_cntrl tests
wam -- run all wam tests
@@ -256,27 +278,114 @@
'''
-def full_usage():
- print FULL_USAGE_MESSAGE
+def rtgen_full_usage():
+ """!Sends to stdout full usage information.
+
+ Prints the RTGEN_FULL_USAGE_MESSAGE to stdout, and exits with
+ status 0. Status 0 is used, to indicate successful execution,
+ since the request to the program is to print the usage
+ information.
+
+ @returns never; exits program with status 0"""
+ print RTGEN_FULL_USAGE_MESSAGE
sys.exit(0)
-def usage(reason):
- sys.stderr.write(SHORT_USAGE_MESSAGE)
+def rtgen_usage(reason):
+ """!Sends to stderr brief usage information, possibly followed by
+ an error message.
+
+ Sends the short usage message (RTGEN_SHORT_USAGE_MESSAGE) to
+ stderr, explaining the program's purpose and how to get more
+ information. If a reason is given, then it is sent to stderr
+ after the string "SCRIP IS ABORTING BECAUSE," followed by non-zero
+ exit. With no reason argument, the exit is 0
+
+ @returns never; exits program
+ @param reason the reason we are aborting, or None to indicate
+ nothing went wrong"""
+ sys.stderr.write(RTGEN_SHORT_USAGE_MESSAGE)
if reason:
sys.stderr.write('\nSCRIPT IS ABORTING BECAUSE: %s\n'%(reason,))
exit(1)
exit(0)
-def initial_checks():
- """!Performs basic sanity checks, such as whether some input files
- are present."""
- if not os.path.isfile('produtil/ush/testgen.py'):
- usage('file produtil/ush/testgen.py does not exist. Are you '
- 'missing the produtil external?')
- if not os.path.isdir('../../NEMS/tests'):
- usage('directory ../../NEMS/tests does not exist. This must '
- 'be part of a NEMS app checkout.')
+RTSH_USAGE_TOP="""Usage: NEMSCompsetRun [options] [test spec [test spec [...] ] ]
+Runs the specified set of tests, and either generates a baseline or
+verifies against an old baseline."""
+
+RTSH_USAGE_SIMPLE=RTSH_USAGE_TOP+""" Run with -h for full usage info.
+"""
+
+RTSH_USAGE_FULL=RTSH_USAGE_TOP+"""
+
+Special modes:
+
+ --dry-run = just print what would be done
+ --resume /path/to/scrub/rtgen.#
+ -r /path/to/scrub/rtgen.#
+ = continue running a workflow in this directory
+ -h | --help = print this message
+
+Test selection options:
+
+ -r /path/rtgen.# | --resume /path/rtgen.#
+ = continue the test in /path/rtgen.# without making a new workflow
+ -f = run all tests (same as test spec '*' )
+ -s = run standard tests (same as test spec "standard")
+ -c SPEC = make baseline for SPEC (same as --baseline SPEC)
+ -t SPEC = run tests in SPEC (-t is superfluous)
+ SPEC = run these tests
+
+Usage and path options:
+
+ --mode=baseline | --baseline = generate a new baseline instead of verifying
+ -p project | --project project = project to use for CPU time
+ --temp-dir /path/to/tmp = scrub area for execution (parent of rtgen.#)
+ -n /path/to/baseline | --baseline-dir /path/to/baseline
+ = specify the location of the baseline to create or verify against
+
+Test SPECifications:
+
+ {test1,test2,test3} = run the tests "test1," "test2," and "test3"
+ gfs = run all tests in set "gfs"
+ * = run all tests (remember to put quotes around this!)
+ union(nested,physics) = run all tests in the "nested" and "physics" sets
+ inter(fv3,nested) = run all nested fv3 tests
+ minus(fv3,nested) = run all fv3 tests except nested tests
+
+Examples:
+
+Generate baseline for all fv3 nested tests. Use a specified temp
+directory and baseline area:
+
+.../NEMSCompsetRun --temp-dir /lfs3/projects/hfv3gfs/$USER/scrub \\
+ --baseline --baseline-dir /lfs3/projects/hfv3gfs/$USER/new-baseline \\
+ 'union(nested,fv3)'
+
+Run all gsm tests that are not wam tests. Automatically decide temp
+areas and use default baseline location. Run all tests in the avn project.
+
+.../NEMSComspetRun -p avn 'minus(gsm,wam)'
+"""
+
+def rtsh_usage(reason):
+ sys.stderr.write(RTSH_USAGE_SIMPLE)
+ if reason:
+ sys.stderr.write('\nSCRIPT IS ABORTING BECAUSE: %s\n'%(reason,))
+ exit(1)
+ exit(0)
+
+def rtsh_full_usage():
+ print RTSH_USAGE_FULL
+ exit(0)
+
+usage = None
+
+########################################################################
+
+########################################################################
+
def username():
"""!Returns the current username. This uses the process's user id
and the pwent database, hence it is less vulnerable to errors than
@@ -285,6 +394,109 @@
@returns the process's current username"""
return pwd.getpwuid(os.getuid()).pw_name
+class RDHPCSAccountParams(object):
+ """!Runs the account_params program and parses the output."""
+ def __init__(self):
+ super(RDHPCSAccountParams,self).__init__()
+ self.logger=logging.getLogger('rtgen')
+ self.first_cpu_project=None
+ self.project_cpu=list()
+ self.first_disk_area=None
+ self.project_disk=list()
+ text=self.run_account_params()
+ if not text: return
+ self.parse_account_params(text)
+
+ def __bool__(self):
+ return self.first_cpu_project is not None
+
+ def __repr__(self):
+ if not self:
+ return '<RDHPCSAccountParams (None)>'
+ return ( '<RDHPCSAccountParams first_cpu_project=%s first_disk_area=%s '
+ 'available cpu=%s disk=%s>'%(
+ repr(self.first_cpu_project),repr(self.first_disk_area),
+ repr(self.project_cpu),repr(self.project_disk)))
+
+ def run_account_params(self):
+ """!Executes the account_params program
+
+ Finds account_params in the PATH and executes it. Captures
+ any output and return value.
+
+ @return None if the exit status of account_params was non-zero.
+ Otherwise, returns the stdout output of account_params"""
+ produtil.log.jlogger.info('run account_params...')
+ try:
+ return produtil.run.runstr(
+ batchexe('account_params'),logger=self.logger)
+ except(EnvironmentError,ExitStatusException) as ee:
+ logger.warning('Cannot run account_params: '+str(ee))
+ return None
+
+ def parse_account_params(self,text):
+ logger=self.logger
+ cpu_projects=list()
+ cpu_avail=dict()
+ disk_areas=list()
+ disk_avail=dict()
+ for m in re.finditer(r'''(?isx)
+ (?:
+ \s* Allocation: \s+ \d+ \s+ (?P<cpuproj>\S+) \s+ (?P<cpuavail>[0-9.]+)
+ \s+ (?P<cpualloc>[0-9.]+) \s+ (?P<cpupct>[0-9.]+)
+ | \s* Directory \s* : \s+ (?P<diskarea>/\S+)
+ \s+ DiskInUse \s* = \s* (?P<diskused>[0-9.]+) [,a-zA-Z \t]+
+ Quota \s* = \s* (?P<diskquota>[0-9.]+)
+ | (?P<ignore> [^\r\n]*[\r\n] | [^\r\n]*\Z ) )
+ ''',text):
+ try:
+ if not m:
+ pass # nothing to do if match failed
+ elif m.group('cpuproj') and m.group('cpuavail'):
+ proj=m.group('cpuproj')
+ avail=100.0-float(m.group('cpupct'))
+ cpu_projects.append(proj)
+ cpu_avail[proj]=avail
+ del proj,avail
+ elif m.group('diskarea') and m.group('diskused') and \
+ m.group('diskquota'):
+ area=m.group('diskarea')
+ used=float(m.group('diskused'))
+ quota=float(m.group('diskquota'))
+ if quota<10000:
+ logger.info('%s: quota<10TB ; will not use this area'%(
+ area,))
+ continue
+ avail=float(max(0,quota-used))/max(1e-3,quota)
+ disk_areas.append(area)
+ disk_avail[area]=avail
+ del used, quota, avail, area
+ else:
+ logger.debug('account_params: no regex match or eoln; ignoring %s'%(
+ repr(m.group(0).strip()),))
+ except(KeyError,ArithmeticError,ValueError,TypeError,IndexError) as e:
+ logger.debug('account_params: error (%s); ignoring %s'%(
+ str(e),repr(m.group(0).strip())))
+
+ if cpu_projects:
+ self.project_cpu=cpu_avail
+ self.first_cpu_project=cpu_projects[0]
+ if disk_areas:
+ self.project_disk=disk_avail
+ self.first_disk_area=disk_areas[0]
+
+parsed_account_params=None
+
+def parse_account_params():
+ global parsed_account_params
+ if parsed_account_params is None:
+ parsed_account_params=RDHPCSAccountParams()
+ return parsed_account_params
+
+########################################################################
+
+# Theia project selection
+
def decide_project_theia():
"""!Chooses which project to use when submitting jobs on Theia.
@@ -413,6 +625,46 @@
logger.warning("%s: randomly chosen stmp"%(use_me,))
return os.path.join(use_me,username())
+########################################################################
+
+# Jet project detection
+
+def decide_tmp_jet():
+ logger=logging.getLogger('rtgen')
+ acct=parse_account_params()
+ for preferred in [
+ '/lfs3/projects/hfv3gfs',
+ '/lfs3/projects/hwrfv3',
+ '/lfs2/projects/gfsenkf',
+ '/pan2/projects/hwrf-vd',
+ acct.first_disk_area ]:
+ if preferred in acct.project_disk and \
+ acct.project_disk[preferred] > 0.95:
+ return os.path.join(preferred,username())
+
+ # Sort disk space by increasing availability
+ areas = [ [area,space] for area,space in acct.project_disk.iteritems() ]
+ areas.sort(lambda a,b: cmp(a[1],b[1]))
+ return os.path.join(areas[-1][0],username())
+
+def decide_project_jet():
+ logger=logging.getLogger('rtgen')
+ acct=parse_account_params()
+ for preferred in [ 'nems', 'hfv3gfs', 'hwrf-vd', 'gfsenkf',
+ 'nceplibs', 'hwrfv3' ]:
+ if preferred in acct.project_cpu and \
+ acct.project_cpu[preferred] > 0.95:
+ return preferred
+
+ # Sort disk space by increasing availability
+ projs = [ [proj,avail] for proj,avail in acct.project_cpu.iteritems() ]
+ projs.sort(lambda a,b: cmp(a[1],b[1]))
+ return projs[-1][0]
+
+########################################################################
+
+# WCOSS project detection
+
def decide_project_wcoss():
"""!Placeholder for future development; returns "GFS-T2O" """
return 'GFS-T2O'
@@ -494,9 +746,10 @@
return os.path.join(max_area,username())
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Custom test generator:
+########################################################################
+# Internal implementation of the test generator
+
class RTGen(TestGen):
def __init__(self,baseline,scratch_dir,unique_id=None,
logger=None,baseline_dir=None,
@@ -528,7 +781,6 @@
if self._new_baseline:
scope.override_local([scope],'plat%BASELINE',self._new_baseline)
if self.project:
- self.logger.warning('override project with '+self.project)
scope.override_local([scope],'plat%CPU_ACCOUNT',self.project)
scope.override_local([scope],'plat%ACCOUNT',self.project)
else:
@@ -543,9 +795,11 @@
def make_more(self,result,con):
self.platform_name=self.scope.resolve('plat%PLATFORM_NAME') \
.string_context(con)
+ assert('/' not in self.platform_name)
self.make_rtrun()
self.make_rtrewind()
self.make_rtreport()
+ self.make_info_sh()
#if self._new_baseline:
# self.make_baseline_dir()
def make_bash_load_rocoto(self,out):
@@ -557,19 +811,24 @@
out.write('module use /hwrf/noscrub/soft/modulefiles\n')
out.write('module load rocoto\n')
out.write('module load ruby # workaround for libxml2 bug\n')
- out.write('module load emc-utils ; have_qoutq=YES\n')
+ out.write('module load emc-utils ; have_qoutql=YES\n')
elif here.name in [ 'surge', 'luna' ]:
out.write('module load xt-lsfhpc\n')
out.write('module use /usrx/local/emc_rocoto/modulefiles\n')
out.write('module load rocoto/issue_8\n')
out.write('module use /gpfs/hps/emc/hwrf/noscrub/soft/modulefiles\n')
- out.write('module load emc-utils ; have_qoutq=YES\n')
+ out.write('module load emc-utils ; have_qoutql=YES\n')
+ elif 'jet' in here.name:
+ out.write('module load hpss rocoto\n')
+ out.write('module use /pan2/projects/hwrf-vd/soft/modulefiles\n')
+ out.write('module load emc-utils\n')
+ out.write('have_qoutql=YES\n')
elif here.name == 'theia':
out.write('module load rocoto\n')
out.write('module use /scratch3/NCEPDEV/hwrf/save/Samuel.Trahan/emc-utils/modulefiles/\n')
- out.write('module load hpss emc-utils ; have_qoutq=YES\n')
+ out.write('module load hpss emc-utils ; have_qoutql=YES\n')
else:
- out.write('have_qoutq=NO\n')
+ out.write('have_qoutql=NO\n')
out.write('work=%s/rocoto\n'%(bashify_string(self.outloc),))
out.write('cd "$work"\n')
out.write('if [[ "$?" != 0 ]] ; then\n')
@@ -585,12 +844,35 @@
self.logger.info('%s: make executable'%(fullpath,))
if not self.dry_run:
os.chmod(fullpath,0755)
+ def make_info_sh(self):
+ contents="""## This script should be sourced by an sh-like shell.
+## It sets useful variables related to the workflow being run
+PLATFORM_NAME={platform_name} ## Name of target platform
+BASELINE_DIR={baseline_dir} ## Directory with baseline data
+BASELINE_TEMPLATE={baseline_template} ## directory with template for new baselines
+UNIQUE_ID={unique_id} ## Unique id used to identify this workflow
+TEMP_AREA={temp_area} ## temporary area, auto-detected or specified at command line
+RUNDIR={run_dir} ## top directory of generated workflow
+SETS='{setarith}' ## set arithmetic specification of which sets to run
+"""
+ contents=contents.format(
+ platform_name=self.scope.resolve('plat%PLATFORM_NAME'),
+ baseline_dir=self.scope.resolve('plat%BASELINE'),
+ baseline_template=self.scope.resolve('plat%BASELINE_TEMPLATE'),
+ unique_id=self.unique_id,
+ temp_area=os.path.dirname(os.path.realpath(self.outloc)),
+ run_dir=self.outloc,
+ setarith=self.setarith
+ )
+ self.make_rtscript(self.outloc,"info.sh.inc",contents)
def make_rtreport(self):
out=StringIO.StringIO()
self.make_bash_load_rocoto(out)
out.write(r'''
+echo "Run rocotostat..." 2>&1
rocotostat -w workflow.xml -d workflow.db -c ALL > rocotostat.txt
timestamp=$( ls -l --time=c --time-style=+%%s workflow.xml | awk '{print $6}' )
+echo "Generate report..." 2>&1
%s/rtreportimpl ../com rocotostat.txt "${1:-txt}" $timestamp > rtreport.txt
cat rtreport.txt
'''%(bashify_string(os.path.realpath(os.path.dirname(__file__))),))
@@ -640,53 +922,6 @@
self.new_baseline,template))
shutil.copytree(template,self.new_baseline,symlinks=True)
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Main program:
-
-def parse_arguments():
- try:
- optval,arglist=getopt.getopt(sys.argv[1:],'vdu:t:bn:i:p:hS')
- except getopt.GetoptError as ge:
- usage(str(ge))
- verbose=0
- dry_run=False
- unique_id=int(os.getpid())
- temp=None
- baseline=False
- baseline_dir=None
- inputfile=None
- project=None
- script_mode=False
- for opt,val in optval:
- if opt=='-v':
- verbose+=1
- elif opt=='-h':
- full_usage() # does not return
- elif opt=='-p':
- project=val
- elif opt=='-d':
- dry_run=True
- elif opt=='-n':
- baseline_dir=val
- elif opt=='-u':
- unique_id=int(val,10)
- elif opt=='-t':
- temp=str(val)
- elif opt=='-b':
- baseline=True
- elif opt=='-i':
- inputfile=val
- elif opt=='-S':
- script_mode=True
- else:
- usage('unknown option '+opt)
- arglist_nowhite=list() # arguments that are not whitespace
- for arg in arglist:
- if not re.match('(?sx) \A \s* \Z',arg):
- arglist_nowhite.append(arg)
- return verbose,baseline_dir,dry_run,baseline,unique_id,temp, \
- inputfile,arglist_nowhite,project,script_mode
-
########################################################################
def verify_fingerprint(baseline,testgen,logger):
@@ -704,8 +939,7 @@
'REGTEST-FINGERPRINT.md')
if not os.path.exists(repo_fingerprint):
- jlogger.warning('No fingerprint file. Skipping fingerprint check.')
- jlogger.warning('Expected: %s'%(repo_fingerprint,))
+ jlogger.info('No fingerprint file. Skipping fingerprint check.')
return
with open(baseline_fingerprint,'r') as base_finger_file:
@@ -730,13 +964,208 @@
repo_fingerprint,))
########################################################################
+# Argument parsing
+########################################################################
-def main():
- verbose,baseline_dir,dry_run,baseline,unique_id,temp, \
- inputfile,arglist,project,script_mode = \
- parse_arguments()
- assert(isinstance(unique_id,int))
+have_setup_produtil=False
+def setup_produtil(jobname,verbose):
+ global have_setup_produtil
+ if have_setup_produtil: return
+ produtil.setup.setup(
+ send_dbn=False, # avoids "dbnalert missing" warnings
+ jobname=jobname, # set job name for jlogfile messages
+ ologlevel=logging.INFO if verbose else logging.WARNING)
+ have_setup_produtil=True
+def parse_rtsh_arguments():
+ """!Argument parser when this script is called as NEMSCompsetRun or rt.sh"""
+ try:
+ optval,arglist=getopt.getopt(sys.argv[1:],"c:fst:n:hr:p:b",[
+ 'project=', 'mode=', 'baseline-dir=', 'baseline',
+ 'dry-run', 'verbose', 'unique-id=', 'temp-dir=',
+ 'resume='])
+ except getopt.GetoptError as ge:
+ rtsh_usage(str(ge))
+
+ verbose=0
+ dry_run=False
+ unique_id=int(os.getpid())
+ temp=None
+ baseline=False
+ baseline_dir=None
+ inputfile=None
+ project=None
+ script_mode=False
+ sets=None
+ resume=None
+ platform_name=None
+ run_dir=None
+ resume_sets=None
+
+ for opt,val in optval:
+ if opt in ['-f','-s','-c','-t'] and sets is not None:
+ rtsh_usage('Only one of -c, -s, -t, or -f can be used.')
+ if opt=='--verbose':
+ verbose+=1
+ elif opt in [ '-h', '--help' ]:
+ rtsh_full_usage()
+ elif opt=='-f':
+ sets='*'
+ elif opt=='-s':
+ sets='standard'
+ elif opt in ['-b','--baseline']:
+ baseline=True
+ elif opt=='-t':
+ sets=str(val)
+ elif opt=='-c':
+ if val in [ 'ompset', 'ompsets' ]:
+ rtsh_usage('The -compset argument is no longer recognized. Use "{compset1,compset2,compset3}" instead. Run with -h for more information.')
+ sets=str(val)
+ baseline=True
+ elif opt in ['-n', '--baseline-dir']:
+ baseline_dir=val
+ elif opt in ['-p', '--project']:
+ project=val
+ elif opt in ['-r', '--resume']:
+ resume=val
+ elif opt=='--mode':
+ if val.lower()=='baseline':
+ baseline=True
+ elif val.lower() in ['execution', 'verify' ]:
+ baseline=False
+ else:
+ rtsh_usage('Unknown run mode '+val)
+ elif opt=='--dry-run':
+ dry_run=True
+ elif opt=='--unique-id':
+ unique_id=int(val,10)
+ elif opt=='--temp-dir':
+ temp=os.path.realpath(str(val))
+ else:
+ rtsh_usage('unknown option '+opt)
+
+ setup_produtil('NEMSCompsetRun',verbose)
+
+ if resume:
+ m=re.match('(?:[A-Z.a-z%]*:)?(\S*)',resume)
+ if not m:
+ rtsh_usage('Resume (-r opt) option must be of the format '
+ 'PLATFORM:/path/to/rtgen.#### or /path/to/rtgen.####')
+ baseline_dir=None
+ unique_id=None
+ temp=None
+ info_sh_inc=os.path.join(resume,'info.sh.inc')
+ with open(info_sh_inc,'rt') as fd:
+ for line in fd:
+ m=re.match('([A-Za-z][A-Za-z0-9_]*)=(.*?) ##',line)
+ if not m: continue
+ (var,val)=m.groups()
+ if var.lower()=='baseline_dir':
+ baseline_dir=os.path.realpath(val)
+ jlogger.info('Baseline directory: %s'%(repr(baseline_dir),))
+ elif var.lower()=='unique_id':
+ unique_id=int(val,10)
+ jlogger.info('Unique id: %s'%(repr(unique_id),))
+ elif var.lower()=='temp_area':
+ temp=os.path.realpath(val)
+ jlogger.info('Temp area: %s'%(repr(temp),))
+ elif var.lower()=='rundir':
+ run_dir=os.path.realpath(val)
+ jlogger.info('Run directory: %s'%(repr(run_dir),))
+ elif var.lower()=='platform_name':
+ platform_name=val
+ jlogger.info('Platform name: %s'%(repr(platform_name),))
+ assert('/' not in platform_name)
+ elif var.lower()=='sets':
+ resume_sets=val[1:-1] # 'set,set,set' => set,set,set
+ jlogger.info('Set specification: %s'%(repr(resume_sets),))
+
+ if baseline_dir is None or unique_id is None or temp is None \
+ or run_dir is None or platform_name is None or resume_sets is None:
+ rtsh_usage('%s: directory has invalid or incomplete info.sh.inc file'%(
+ info_sh_inc))
+
+ arglist_nowhite=list() # arguments that are not whitespace
+ if sets: arglist_nowhite.append(sets)
+ if resume:
+ if resume_sets:
+ arglist_nowhite.append(resume_sets)
+ else:
+ arglist_nowhite.append('*') # * = all known tests
+
+ for arg in arglist:
+ if not re.match('(?sx) \A \s* \Z',arg):
+ arglist_nowhite.append(arg)
+
+ if not arglist_nowhite and not resume:
+ rtsh_usage('You must specify which tests to run')
+
+ return verbose,baseline_dir,dry_run,baseline,unique_id,temp, \
+ inputfile,arglist_nowhite,project,script_mode,resume, \
+ platform_name, run_dir
+
+########################################################################
+
+def parse_rtgen_arguments():
+ try:
+ optval,arglist=getopt.getopt(sys.argv[1:],'vdu:t:bn:i:p:hS',
+ 'project=', 'mode=', 'baseline-dir=', 'baseline',
+ 'dry-run', 'verbose', 'unique-id=', 'temp-dir=',
+ 'resume=', 'help', 'input-file')
+ except getopt.GetoptError as ge:
+ rtgen_usage(str(ge))
+
+ verbose=0
+ dry_run=False
+ unique_id=int(os.getpid())
+ temp=None
+ baseline=False
+ baseline_dir=None
+ inputfile=None
+ project=None
+ script_mode=False
+ for opt,val in optval:
+ if opt in ['-v', '--verbose']:
+ verbose+=1
+ elif opt in ['-h', '--help']:
+ rtgen_full_usage() # does not return
+ elif opt in ['-p', '--project']:
+ project=val
+ elif opt in ['-d', '--dry-run']:
+ dry_run=True
+ elif opt in ['-b', '--baseline']:
+ baseline=True
+ elif opt in ['-n', '--baseline-dir']:
+ baseline_dir=val
+ elif opt in ['-u', '--unique-id']:
+ unique_id=int(val,10)
+ elif opt in ['-t', '--temp-dir']:
+ temp=str(val)
+ elif opt in ['-b', '--baseline']:
+ baseline=True
+ elif opt in ['-i', '--input-file']:
+ inputfile=val
+ elif opt=='-S':
+ script_mode=True
+ else:
+ rtgen_usage('unknown option '+opt)
+ arglist_nowhite=list() # arguments that are not whitespace
+ for arg in arglist:
+ if not re.match('(?sx) \A \s* \Z',arg):
+ arglist_nowhite.append(arg)
+ setup_produtil('rtgen',verbose)
+ return verbose,baseline_dir,dry_run,baseline,unique_id,temp, \
+ inputfile,arglist_nowhite,project,script_mode
+
+########################################################################
+# Main program for rtgen
+########################################################################
+
+def rtgen(verbose,baseline_dir,dry_run,baseline,unique_id,temp,
+ inputfile,arglist,project,script_mode, logger,
+ send_rtrun_instructions):
+
+ ## Generate the set arithmetic string
if len(arglist)>1:
arith='union('+','.join(arglist)+')'
elif arglist:
@@ -750,23 +1179,23 @@
else:
arith='baseline'
- # Initialize the produtil package.
- produtil.setup.setup(
- send_dbn=False, # avoids "dbnalert missing" warnings
- jobname='rtgen', # set job name for jlogfile messages
- ologlevel=logging.INFO if verbose else logging.WARNING)
- logger=logging.getLogger('rtgen')
+ # Let the user know which set we are running:
if arith is None:
jlogger.info('Will run all known tests.')
else:
jlogger.info('Test suite subset = %s'%(arith,))
+ ## Decide the project:
if project is None:
if produtil.cluster.name() == 'theia':
project=decide_project_theia()
elif produtil.cluster.name() in ['gyre','tide','luna','surge']:
project=decide_project_wcoss()
+ elif produtil.cluster.name() == 'jet':
+ project=decide_project_jet()
+ assert('aoml' not in project)
+ assert('hfip' not in project)
else:
fail('Unknown system. Only Theia and WCOSS Phase 1 are supported.')
jlogger.info('Auto-chosen project for job submission is %s'%(
@@ -775,11 +1204,19 @@
jlogger.info('User-provided project for job submission is %s'%(
repr(project),))
+ ## Decide the temp area
if temp is None:
if produtil.cluster.name() == 'theia':
scratch_dir=decide_tmp_theia()
elif produtil.cluster.name() in ['gyre','tide','luna','surge']:
scratch_dir=decide_tmp_wcoss(produtil.cluster.where().wcoss_phase)
+ elif produtil.cluster.name() == 'jet':
+ fail('Specify the temp dir when running on Jet. Example --temp-dir /lfs3/projects/hfv3gfs/$USER/scrub')
+ scratch_dir=decide_tmp_jet()
+ assert('aoml' not in scratch_dir)
+ assert('hfip' not in scratch_dir)
+ assert('nceplibs' not in scratch_dir)
+ assert('hwrfdata' not in scratch_dir)
else:
fail('Unknown system. Only Theia and WCOSS Phase 1 are supported.')
jlogger.info('Auto-chosen ptmp is %s'%(repr(scratch_dir),))
@@ -825,7 +1262,8 @@
if script_mode:
print "RUNDIR='%s' ; PLATFORM_NAME='%s'"%(
testgen.outloc, testgen.platform_name)
- else:
+ assert('/' not in testgen.platform_name)
+ elif send_rtrun_instructions:
print r'''You need to run the test now. You have three options:
OPTION 1: Put this in your cron:
*/3 * * * * %s/rtrun --step --zero-exit > %s/rtrun-cron.log 2>&1
@@ -841,8 +1279,159 @@
testgen.outloc,
testgen.outloc,
testgen.outloc)
- # Last line must print the RUNDIR= for calling process
- exit(0)
+ return testgen.platform_name, testgen.outloc, scratch_dir
+
+########################################################################
+# Utilities for rt.sh and NEMSCompsetRun modes
+########################################################################
+
+def run_rtrun(run_dir,logger,verbose):
+ cmd=batchexe(os.path.join(run_dir,'rtrun'))['--loop']
+ if verbose: cmd=cmd['-v']
+ result=run(cmd,logger=logger)
+ return result==0
+
+def guess_app_dir():
+ here=os.path.dirname(__file__)
+ if not os.path.isabs(here):
+ here=os.path.abspath(here)
+ for rel in ['.','..','../../','../../../']:
+ trydir=os.path.join(here,rel)
+ if os.path.exists(os.path.join(trydir,'NEMS/src/conf')):
+ return trydir
+ raise Exception("Cannot find app directory (parent of NEMS). Looked for NEMS/src/conf relative to ., .., ../.., and ../../.. but found none.")
+
+def run_rtreport(run_dir,app_dir,platform,logger):
+ jlogger.info('generate report')
+
+ # Target directory for reports:
+ log_dir=os.path.join(app_dir,'log','report-'+platform+'-log')
+ produtil.fileop.makedirs(log_dir,logger=logger)
+
+ # Copy log files to log directory
+ jlogger.info('copy build logs to %s'%(log_dir,))
+ try:
+ for src in glob.glob(os.path.join(run_dir,'tmp/log','build*')):
+ tgt=os.path.join(log_dir,os.path.basename(src))
+ produtil.fileop.deliver_file(src,tgt,logger=logger)
+ except EnvironmentError as ee:
+ logger.error('cannot copy build logs: '+str(ee))
+ return False
+
+ # Run rtreport
+ report=os.path.join(log_dir,'rtreport.txt')
+ status=run(batchexe(os.path.join(run_dir,'rtreport')) > report)
+ success=False
+ if status==0:
+ for line in fileinput.input(report):
+ if line.find('REGRESSION TEST WAS SUCCESSFUL')>=0:
+ success=True
+ break
+ if success:
+ print 'Report says test succeeded.'
+ else:
+ print 'Report says at least one test failed.'
+ print 'For details, look in %s'%(report,)
+ else:
+ print 'Non-zero exit status from rtreport. Test failed.'
+ return success
+
+def called_as_what():
+ if len(sys.argv)>1:
+ if sys.argv[1]=='--NEMSCompsetRun':
+ sys.argv=[sys.argv[0]]+sys.argv[2:]
+ return 'NEMSCompsetRun'
+ return 'rtgen'
+
+########################################################################
+# Main entry point for all programs
+########################################################################
+
+def main():
+
+ ## Ensure we're in the NEMS/tests directory:
+ if not os.path.isdir('produtil') or not os.path.exists('rtgen'):
+ os.chdir(os.path.dirname(os.path.realpath(__file__)))
+ if not os.path.isdir('produtil') or not os.path.exists('rtgen'):
+ sys.stderr.write('Cannot find NEMS/tests directory.\nPlease try running this script from your NEMS/tests directory.\n')
+ exit(1)
+
+ # Should we behave as NEMSCompsetRun or rtgen?
+ called_as=called_as_what()
+
+ global usage
+ if called_as=='rtgen':
+ verbose,baseline_dir,dry_run,baseline,unique_id,scratch_dir, \
+ inputfile,arglist,project,script_mode = \
+ parse_rtgen_arguments()
+ usage=rtgen_usage
+ resume=False
+ assert(False)
+ else:
+ verbose,baseline_dir,dry_run,baseline,unique_id,scratch_dir, \
+ inputfile,arglist,project,script_mode,resume, \
+ platform_name, run_dir = \
+ parse_rtsh_arguments()
+ usage=rtsh_usage
+
+ assert(isinstance(unique_id,int))
+
+ # Initialize the produtil package. This must be done after
+ # argument parsing due to the verbosity setting.
+ setup_produtil('NEMSCompsetRun',True)
+ logger=logging.getLogger(called_as)
+
+ logger.info('Running as '+called_as)
+
+# if not verbose:
+# sys.tracebacklimit=0
+
+ # Now we generate the workflow if that was requested.
+ ( platform_name, run_dir, scratch_dir ) = \
+ rtgen(verbose,baseline_dir,dry_run,baseline,unique_id,scratch_dir,
+ inputfile,arglist,project,script_mode,logger,
+ called_as=='rtgen')
+ assert('/' not in platform_name)
+
+ if called_as=='rtgen': exit(0)
+
+ app_dir=guess_app_dir()
+
+ # If we get to this point, we are called as rt.sh or
+ # NEMSCompsetRun, and hence we must run the test suite.
+ logger=logging.getLogger('NEMSCompsetRun')
+ # Note we use scratch_dir because it is what rtgen returned.
+ run_dir=os.path.join(scratch_dir,'rtgen.%d'%unique_id)
+
+ # In dry run mode, we just print a few messages, and we're done.
+ if dry_run:
+ logger.info('Would run rtrun in '+run_dir)
+ logger.info('Would check rtreport in '+run_dir)
+ exit(0)
+
+ if not os.path.isdir(run_dir):
+ logger.error('%s: no such directory; rtgen failed or was never run'%(
+ run_dir))
+ exit(1)
+
+ # Run the rtrun program to execute the workflow.
+ # Note: verbose is hard-coded to true to ensure -v option
+ success=run_rtrun(run_dir,logger,True)
+ if not success:
+ logger.warning('%s: rtrun exited with non-zero status'%(
+ os.path.join(run_dir,'rtrun')))
+
+ # Generate the report if we are in verification mode.
+ if not baseline:
+ if dry_run:
+ logger.info('Would check rtreport.')
+ report_success=run_rtreport(run_dir,app_dir,platform_name,logger)
+ success = success and report_success
+ print 'TEST RESULT: ' + ( 'PASS' if success else 'FAIL' )
+ else:
+ print 'BASELINE GENERATION: ' + \
+ ( 'SUCCESS' if success else 'FAILURE' )
+
if __name__=='__main__':
main()
Index: checkout/tests/rt.sh
===================================================================
--- checkout/tests/rt.sh (revision 90943)
+++ checkout/tests/rt.sh (revision 92559)
@@ -1,222 +1,18 @@
#! /bin/bash
-# NOTE: This script is a bash script. It uses bash-specific features
-# and cannot run correctly under other shells.
+for loc in . ./tests ./NEMS/tests ../tests ../NEMS/tests ; do
+ if [[ -x "$loc/rtgen" ]] ; then
+ cd $loc
+ # Get the fully qualified path:
+ real_loc=$( pwd -P )
-function die {
- echo "$*" 1>&2
- exit 1
-}
+ # Ensure our produtil is first in $PYTHONPATH
+ export PYTHONPATH=$real_loc/produtil/ush${PYTHONPATH:+:$PYTHONPATH}
-function usage {
- set +x
- echo
- echo "Usage: $0 -c <subset> | -f | -s | -t <subset> | -n /path/to/baseline | -h"
- echo
- echo " -c <subset> = create new baseline results for <subset>"
- echo " -f run full suite of regression tests"
- echo " -s run standard suite of regression tests (same as -t standard)"
- echo " -t <subset> = runs specified subset of tests"
- echo " -n /path/to/baseline = specify path to REGRESSION_TEST directory"
- echo " -h display this help"
- echo " -r PLATFORM:/path/to/run"
- echo " rerun past suite without regenerating it"
- echo " -p project = set the project to use for cpu time"
- echo
- echo "Common <subset>s: gfs, nmm, slg, wam, debug"
- echo "See ../../compsets/all.input for a full list"
- echo
- if [[ ! -z "$*" ]] ; then
- echo "SCRIPT ABORTING: $*" 1>&2
- fi
- exit 1
-}
-
-if [[ -d NEMS/tests ]] ; then
- cd NEMS/tests
-elif [[ -s tests/rtgen ]] ; then
- cd tests
-elif [[ ! -s rtgen ]] ; then
- die Run this script from the NEMS/tests directory.
-fi
-
-set_info=''
-cmd='./rtgen -S '
-baseline=NO
-rerun=NO
-RUNDIR=''
-PLATFORM_NAME=''
-
-export PYTHONPATH=$( pwd -P )/produtil/ush${PYTHONPATH:+:$PYTHONPATH}
-
-while getopts ":c:fst:n:hr:p:" opt; do
- case $opt in
- r)
- if [[ $OPTARG =~ ^([a-zA-Z][a-zA-Z_.0-9]*):(.+)$ ]] ; then
- PLATFORM_NAME="${BASH_REMATCH[1]}"
- RUNDIR="${BASH_REMATCH[2]}"
- rerun=YES
- else
- echo "${BASH_REMATCH[@]}"
- usage "Rerun argument must be PLATFORM_NAME:RUNDIR"
- fi
- ;;
- p)
- cmd="$cmd -p $OPTARG"
- ;;
- c)
- if [[ ! -z "$set_info" ]] ; then
- usage "Only one of -c, -s, -t, or -f can be used."
- fi
- set_info="$OPTARG"
- cmd="$cmd -b"
- baseline=YES
- ;;
- s)
- if [[ ! -z "$set_info" ]] ; then
- usage "Only one of -c, -s, -t, or -f can be used."
- fi
- set_info='standard'
- ;;
- f)
- if [[ ! -z "$set_info" ]] ; then
- usage "Only one of -c, -s, -t, or -f can be used."
- fi
- set_info=' '
- ;;
- h)
- usage
- ;;
- t)
- if [[ ! -z "$set_info" ]] ; then
- usage "Only one of -c, -s, -t, or -f can be used."
- fi
- set_info="$OPTARG"
- ;;
- n)
- cmd="$cmd -n $OPTARG"
- ;;
- \?)
- usage "Unknown option -$OPTARG"
- ;;
- :)
- usage "Option -$OPTARG requires an argument."
- ;;
- esac
+ # Run rtgen as "rt.sh"
+ exec $real_loc/rtgen --NEMSCompsetRun "$@"
+ fi
done
-if [[ ! -z "$set_info" ]] ; then
- cmd="$cmd $set_info"
-fi
-
-if [[ -z "$set_info" && "$rerun" == NO ]] ; then
- usage "At least one of -n, -c, -t, -f or -s must be specified."
-fi
-
-if [[ ! -z "$model" && ! -z "$fullstd" ]] ; then
- cmd="$cmd 'union($model,$fullstd)'"
-elif [[ ! -z "$model" || ! -z "$fullstd" ]] ; then
- cmd="$cmd '$model$fullstd'"
-fi
-
-# Arcane bash magic below. This is what it does:
-#
-# $cmd
-# ^-- Runs rtgen
-#
-# $cmd < /dev/null
-# ^-- Workaround for Jet bug: do not send stdin on a batch node
-#
-# $cmd < /dev/null | tee >(cat >&2)
-# ^--- Copy stdout to stderr
-#
-# $cmd < /dev/null | tee >(cat >&2) | grep 'RUNDIR=' | tail -1
-# Get the RUNDIR variable ---^---------------^
-#
-# The result is that $cmd's stdout will go to the terminal AND to the
-# "grep | tail". The last line will end up in $result
-#
-# result='RUNDIR=/path/to/rundir PLATFORM_NAME=wcoss.cray'
-
-SUCCESS=PASS
-
-if [[ "$rerun" == NO ]] ; then
- # When we're not rerunning, we need to generate a new workflow area.
-
- echo "rt.sh: will run $cmd"
-
- result=$( $cmd < /dev/null | tee >(cat >&2) | grep 'RUNDIR=' | tail -1 )
- eval $result
-
- if [[ -z "$RUNDIR" ]] ; then
- die "ERROR: The rtgen script failed (no RUNDIR). See above for details."
- fi
- if [[ -z "$PLATFORM_NAME" ]] ; then
- die "ERROR: The rtgen script failed (no PLATFORM_NAME). See above for details."
- fi
-else
- : # if we get here, $cmd is not used
-fi
-
-cmd="$RUNDIR/rtrun --loop -v"
-echo "rt.sh: will run $cmd"
-
-$cmd # runs for a long time
-status="$?"
-
-if [[ "$status" != 0 ]] ; then
- SUCCESS=FAIL
-fi
-
-LOGDIR="../../log/report-$PLATFORM_NAME-log"
-REPORT="$LOGDIR/rtreport.txt"
-
-if [[ "$baseline" == NO ]] ; then
- echo "rt.sh: time to generate the report"
- if [[ ! -d "$RUNDIR" ]] ; then
- echo "rt.sh: run area does not exist: $RUNDIR"
- die "rt.sh: workflow did not run there"
- fi
- echo "rt.sh: copy build logs to $LOGDIR"
- mkdir -p "$LOGDIR"
- if ( ! cp -fp "$RUNDIR/tmp/log/build"* "$LOGDIR/." ) ; then
- die "rt.sh: could not copy build logs. Missing file? I/O error?"
- fi
- cmd="$RUNDIR/rtreport > $REPORT"
- echo "rt.sh: run $cmd"
- "$RUNDIR/rtreport" > "$REPORT"
- repstatus="$?"
- echo "rt.sh: status $repstatus"
- if [[ "$repstatus" == 0 ]] ; then
- if ( ! grep 'REGRESSION TEST WAS SUCCESSFUL' "$REPORT" > /dev/null ) ; then
- echo "rt.sh: report says at least one test failed."
- echo "rt.sh: for details, look in $( pwd )/$REPORT"
- SUCCESS=FAIL
- else
- echo "rt.sh: report says test succeeded."
- fi
- else
- die "rt.sh: could not copy report. Missing file? I/O error?"
- fi
-fi
-
-echo
-echo "The test directory is"
-echo " $RUNDIR"
-echo "Execution area: $RUNDIR/tmp"
-echo "Temporary log files: $RUNDIR/tmp/log"
-echo "Subversion log files: $( pwd )/$LOGDIR"
-echo "Exit status of rtrun: $status"
-echo
-echo "TEST RESULT: $SUCCESS"
-echo
-
-if [[ "$SUCCESS" == PASS ]] ; then
- echo "Success: rejoice! All tests passed."
-else
- echo "I deeply apologize, but at least one test failed."
- echo "You should fix the problem, and then use rtrewind"
- echo "and rtrun to re-run failed tests."
-fi
-
-exit $status
+echo "Cannot find rtgen! Try running from NEMS/tests directory."
+exit -1
\ No newline at end of file
Index: checkout/tests
===================================================================
--- checkout/tests (revision 90943)
+++ checkout/tests (revision 92559)
Property changes on: checkout/tests
___________________________________________________________________
Modified: svn:externals
## -1 +1 ##
-produtil -r90581 https://svnemc.ncep.noaa.gov/projects/nceplibs/produtil/branches/regtests-run
+produtil -r92558 https://svnemc.ncep.noaa.gov/projects/nceplibs/produtil/branches/regtests-run
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /nems/branches/fv3-jet/tests:r89946-92482
Index: checkout/doc/Makefile
===================================================================
--- checkout/doc/Makefile (revision 90943)
+++ checkout/doc/Makefile (revision 92559)
@@ -1,7 +1,12 @@
NEMSDOC=markdown.md BUILD.md NEWTEST.md OLDTEST.md
-APPDOC=../../doc/README.md
#MODELDOC=modeldoc.md README.GFS.md README.NMM.md
+ifneq ($(wildcard ../../doc/*.md),)
+APPDOC=../../doc/*.md
+else
+APPDOC=
+endif
+
ALLDOC=$(APPDOC) $(NEMSDOC) # $(MODELDOC)
@@ -10,7 +15,7 @@
clean:
rm -f README.html
-README.html: $(ALLDOC)
+README.html: $(ALLDOC) Makefile
./md2html.py $(ALLDOC) README.html
head README.html
Index: checkout/src
===================================================================
--- checkout/src (revision 90943)
+++ checkout/src (revision 92559)
Property changes on: checkout/src
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /nems/branches/fv3-jet/src:r89946-92482
Index: checkout
===================================================================
--- checkout (revision 90943)
+++ checkout (revision 92559)
Property changes on: checkout
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /nems/branches/fv3-jet:r89946-92482
--=_59121bc9.mxbY+RCbbOnLoVlWRkmLNZdlDm0kOUig//vPB7KM/+3cESLJ--
More information about the Ncep.list.nems.announce
mailing list