diff --git a/bin/cylc-suite-state b/bin/cylc-suite-state index 445871cc1c3..dec2032e5b6 100755 --- a/bin/cylc-suite-state +++ b/bin/cylc-suite-state @@ -64,6 +64,7 @@ from cylc.dbstatecheck import ( from cylc.cfgspec.globalcfg import GLOBAL_CFG from cylc.command_polling import Poller from cylc.task_state import TASK_STATUSES_ORDERED +from cylc.cycling.loader import get_point from isodatetime.parsers import TimePointParser, DurationParser @@ -105,7 +106,16 @@ class SuitePoller(Poller): sleep(self.interval) if cylc.flags.verbose: sys.stdout.write('\n') - return connected + + if connected and self.args['cycle']: + fmt = self.args['template'] + if not fmt: + fmt = self.checker.get_remote_point_format() + if fmt: + my_parser = TimePointParser() + my_point = my_parser.parse(self.args['cycle'], dump_format=fmt) + self.args['cycle'] = str(my_point) + return connected, self.args['cycle'] def check(self): # return True if desired suite state achieved, else False @@ -211,7 +221,7 @@ def main(): except ValueError: sys.exit("ERROR: Cannot parse offset: %s" % options.offset) if oper == "-": - my_target_point -= my_shift + my_target_point -= my_shiftcycle_point_format else: my_target_point += my_shift else: @@ -233,14 +243,8 @@ def main(): sys.exit("ERROR: invalid status '" + options.status + "'") # Reformat cycle point for querying targeted suite - if options.template: - if options.cycle: - my_parser = TimePointParser() - my_target_point = my_parser.parse(options.cycle, - dump_format=options.template) - options.cycle = str(my_target_point) - else: - sys.exit("ERROR: No cycle point to reformat using template") + if options.template and not options.cycle: + sys.exit("ERROR: No cycle point to reformat using template") # this only runs locally (use of --host or --user results in remote # re-invocation). @@ -253,7 +257,8 @@ def main(): 'task': options.task, 'cycle': options.cycle, 'status': options.status, - 'message': options.msg + 'message': options.msg, + 'template': options.template } spoller = SuitePoller("requested state", @@ -261,7 +266,9 @@ def main(): options.max_polls, args=pollargs) - if not spoller.connect(): + connected, formatted_pt = spoller.connect() + + if not connected: sys.exit("ERROR: cannot connect to the suite DB") if options.status and options.task and options.cycle: @@ -279,7 +286,7 @@ def main(): spoller.checker.display_maps( spoller.checker.suite_state_query( task=options.task, - cycle=options.cycle, + cycle=formatted_pt, status=options.status)) diff --git a/lib/cylc/dbstatecheck.py b/lib/cylc/dbstatecheck.py index 922416fcfcd..5112b5b6031 100644 --- a/lib/cylc/dbstatecheck.py +++ b/lib/cylc/dbstatecheck.py @@ -76,6 +76,16 @@ def display_maps(self, res): for row in res: sys.stdout.write((", ").join(row).encode("utf-8") + "\n") + def get_remote_point_format(self): + """Query a remote suite database for a 'cycle point format' entry""" + q = "select value from suite_params where key==?" + vals = ['cycle_point_format'] + self.c.execute(q, vals) + res = self.c.fetchone() + if res: + return res[0] + return None + def state_lookup(self, state): """allows for multiple states to be searched via a status alias""" if state in self.STATE_ALIASES: diff --git a/lib/cylc/scheduler.py b/lib/cylc/scheduler.py index 309bc821213..01fc8373943 100644 --- a/lib/cylc/scheduler.py +++ b/lib/cylc/scheduler.py @@ -415,7 +415,10 @@ def configure(self): self.load_tasks_for_run() self.profiler.log_memory("scheduler.py: after load_tasks") - self.pool.put_rundb_suite_params(self.initial_point, self.final_point) + self.pool.put_rundb_suite_params( + self.initial_point, + self.final_point, + self.config.cfg['cylc']['cycle point format']) self.pool.put_rundb_suite_template_vars(self.template_vars) self.configure_suite_environment() @@ -943,7 +946,10 @@ def command_reload_suite(self): self.configure_suite_environment() if self.gen_reference_log or self.reference_test_mode: self.configure_reftest(recon=True) - self.pool.put_rundb_suite_params(self.initial_point, self.final_point) + self.pool.put_rundb_suite_params( + self.initial_point, + self.final_point, + self.config.cfg['cylc']['cycle point format']) self.do_update_state_summary = True def command_set_runahead(self, interval=None): diff --git a/lib/cylc/task_pool.py b/lib/cylc/task_pool.py index d6676be5b99..a24b05a90d0 100644 --- a/lib/cylc/task_pool.py +++ b/lib/cylc/task_pool.py @@ -1420,7 +1420,7 @@ def match_ext_triggers(self): if itask.state.external_triggers: ets.retrieve(itask) - def put_rundb_suite_params(self, initial_point, final_point): + def put_rundb_suite_params(self, initial_point, final_point, format=None): """Put run mode, initial/final cycle point in runtime database. This method queues the relevant insert statements. @@ -1430,6 +1430,10 @@ def put_rundb_suite_params(self, initial_point, final_point): {"key": "initial_point", "value": str(initial_point)}, {"key": "final_point", "value": str(final_point)}, ]) + if format: + self.db_inserts_map[self.TABLE_SUITE_PARAMS].extend([ + {"key": "cycle_point_format", "value": str(format)} + ]) if self.is_held: self.db_inserts_map[self.TABLE_SUITE_PARAMS].append( {"key": "is_held", "value": 1}) diff --git a/tests/suite-state/06-format.t b/tests/suite-state/06-format.t new file mode 100755 index 00000000000..3e8b7fa71b8 --- /dev/null +++ b/tests/suite-state/06-format.t @@ -0,0 +1,43 @@ +#!/bin/bash +# THIS FILE IS PART OF THE CYLC SUITE ENGINE. +# Copyright (C) 2008-2017 NIWA +# +# 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 . +#------------------------------------------------------------------------------- +# Test cylc suite-state "template" option +. $(dirname $0)/test_header +#------------------------------------------------------------------------------- +set_test_number 5 +#------------------------------------------------------------------------------- +install_suite $TEST_NAME_BASE format +#------------------------------------------------------------------------------- +TEST_NAME=$TEST_NAME_BASE-run +suite_run_ok $TEST_NAME cylc run --debug $SUITE_NAME +#------------------------------------------------------------------------------- +TEST_NAME=$TEST_NAME_BASE-cli-template-poll +run_ok $TEST_NAME cylc suite-state $SUITE_NAME -p 20100101T0000Z \ + --task=foo --status=succeeded +contains_ok $TEST_NAME.stdout <<__OUT__ +polling for 'succeeded': satisfied +__OUT__ +#------------------------------------------------------------------------------- +TEST_NAME=$TEST_NAME_BASE-cli-template-dump +run_ok $TEST_NAME cylc suite-state $SUITE_NAME -p 20100101T0000Z +contains_ok $TEST_NAME.stdout <<__OUT__ +foo, 2010-01-01, succeeded +__OUT__ +#------------------------------------------------------------------------------- +purge_suite $SUITE_NAME +#------------------------------------------------------------------------------- +exit 0 diff --git a/tests/suite-state/format/suite.rc b/tests/suite-state/format/suite.rc new file mode 100644 index 00000000000..ec3e4270a4e --- /dev/null +++ b/tests/suite-state/format/suite.rc @@ -0,0 +1,16 @@ +[cylc] + UTC mode = True + cycle point format = CCYY-MM-DD + [[reference test]] + live mode suite timeout = PT1M + +[scheduling] + initial cycle point = 20100101 + +[[dependencies]] + [[[R1]]] + graph = foo + +[runtime] + [[foo]] + script = true