1#!/usr/local/bin/python3.8 2 3# @HEADER 4# ************************************************************************ 5# 6# TriBITS: Tribal Build, Integrate, and Test System 7# Copyright 2013 Sandia Corporation 8# 9# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, 10# the U.S. Government retains certain rights in this software. 11# 12# Redistribution and use in source and binary forms, with or without 13# modification, are permitted provided that the following conditions are 14# met: 15# 16# 1. Redistributions of source code must retain the above copyright 17# notice, this list of conditions and the following disclaimer. 18# 19# 2. Redistributions in binary form must reproduce the above copyright 20# notice, this list of conditions and the following disclaimer in the 21# documentation and/or other materials provided with the distribution. 22# 23# 3. Neither the name of the Corporation nor the names of the 24# contributors may be used to endorse or promote products derived from 25# this software without specific prior written permission. 26# 27# THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY 28# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE 31# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 32# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 33# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 34# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 35# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 36# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 37# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38# 39# ************************************************************************ 40# @HEADER 41 42 43# TODO: Put a time limit on the command so that it will not run past the 44# RUNTILL time. You could do this by running a cmake -P driver script that 45# calls EXECUTE_PROCESS(...). There is also some python code that exists out 46# there that could also implement a time limit but it is complex. 47 48 49# 50# Read in the command-line arguments 51# 52 53usageHelp = r"""generic-looping-demon.py [OPTIONS] 54 55This simple program takes a command as input and runs it over and over again 56(pausing in-between iterations for a given time) and then stops at the given 57abolute time. 58 59The reason that the script takes an absolute time instead of a relative time 60is that this script is desiged to drive continuous itegration (CI) processes 61where the CI process should shut down at some point. 62 63NOTE: The last iteration will not start later than --run-till=RUNTILL but the 64last command could run until significantly after that time. 65""" 66 67from optparse import OptionParser 68 69clp = OptionParser(usage=usageHelp) 70 71clp.add_option( 72 "--command", dest="command", type="string", default="", 73 help="The shell command that will get run in the loop" ) 74 75clp.add_option( 76 "--loop-interval", dest="loopInterval", type="string", default="", 77 help="Input to the standard unix/linux 'sleep' command" \ 78 +" (e.g. '60s') to space out iterations of the script.") 79 80dateFormat = "%Y-%m-%d" 81timeFormat = "%H:%M:%S" 82dateTimeFormat = dateFormat+" "+timeFormat 83clp.add_option( 84 "--run-till", dest="runTill", type="string", default="", 85 help="The absolute time the script will run iterations till." \ 86 +" This takes the format "+dateTimeFormat+" (e.g. 2011-06-09 18:00:00).") 87 88clp.add_option( 89 "--today-run-till", dest="todayRunTill", type="string", default="", 90 help="The time today the script will run iterations till." \ 91 +" This takes the format "+timeFormat+" (e.g. 18:00:00).") 92 93clp.add_option( 94 "--pause-file", dest="pauseFile", type="string", default="", 95 help="The name of a file, that if exists, will prevent command" \ 96 +" from being run.") 97 98 99(options, args) = clp.parse_args() 100 101 102# 103# Check the input arguments 104# 105 106import sys 107 108if not options.command: 109 print("\nError, you must set the --command argument!") 110 sys.exit(1) 111 112if not options.loopInterval: 113 print("\nError, you must set the --loop-interval argument!") 114 sys.exit(1) 115 116if not (options.runTill or options.todayRunTill): 117 print("\nError, you must set either the --run-till or --today-run-till argument!") 118 sys.exit(1) 119 120 121# 122# Echo the command-line 123# 124 125print("") 126print("**************************************************************************") 127print("Script: generic-looping-demon.py \\") 128print(" --command='" + options.command + "' \\") 129print(" --loop-interval='" + options.loopInterval + "' \\") 130 131if options.runTill: 132 print(" --run-till='" + options.runTill + "' \\") 133if options.todayRunTill: 134 print(" --run-till='" + options.todayRunTill + "' \\") 135print(" --pause-file='" + options.pauseFile + "' \\") 136 137 138# 139# Helper functions 140# 141 142# Parses "%Y-%m-%d %H:%M:%S" into a datetime.datetime object 143def parseDateTimeString(dateTimeStr): 144 (dateStr, timeStr) = dateTimeStr.split(" ") 145 (year, month, day) = dateStr.split("-") 146 (hour, minute, second) = timeStr.split(":") 147 return datetime.datetime(int(year), int(month), int(day), 148 int(hour), int(minute), int(second)) 149 150 151def formatDateTime(dateTimeObj): 152 return datetime.datetime.strftime(dateTimeObj, dateTimeFormat) 153 154 155def pauseFileExists(pauseFile): 156 if pauseFile and os.path.exists(pauseFile): 157 return True 158 return False 159 160# 161# Executable statements 162# 163 164import os 165import datetime 166 167scriptsDir = os.path.abspath(os.path.dirname(sys.argv[0]))+"/cmake/python" 168sys.path.insert(0, scriptsDir) 169 170from GeneralScriptSupport import * 171 172if options.runTill: 173 finalDateTime = parseDateTimeString(options.runTill) 174elif options.todayRunTill: 175 todayDate = datetime.datetime.today() 176 todayDateStr = datetime.datetime.strftime(todayDate, dateFormat) 177 finalDateTime = parseDateTimeString(todayDateStr+" "+options.todayRunTill) 178 179if pauseFileExists(options.pauseFile): 180 print("\nThe file " + options.pauseFile + " exists at start so deleteing it!") 181 os.remove(options.pauseFile) 182 183print("\nThe script will run iterations till = " + formatDateTime(finalDateTime) 184 + "\n") 185 186currentTime = datetime.datetime.now() 187iteration = 0 188 189while currentTime < finalDateTime: 190 print("*********************************************************************" 191 "********\n" + str(iteration) + ":" + " current time = " + 192 formatDateTime(currentTime) + ", final time = " + 193 formatDateTime(finalDateTime)) 194 if pauseFileExists(options.pauseFile): 195 print("\nThe file " + options.pauseFile + " exists so skipping this iteration!") 196 else: 197 echoRunSysCmnd(options.command, throwExcept=False, timeCmnd=True) 198 echoRunSysCmnd("sleep "+options.loopInterval) 199 currentTime = datetime.datetime.now() 200 iteration += 1 201