#********************************************************************
#
# Copyright (C) 2005-2006 Hari Krishna Dara
#
# This file is part of p4admin.
#
# p4admin 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 2
# of the License, or (at your option) any later version.
#
# p4admin 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
#*******************************************************************
import time
import sys
import sys
import os
import os.path
import threading
import logging
import utils
log = logging.getLogger(__name__)
# From pyunit#unittestgui.py
class RollbackImporter:
"""This class is used to make sure that all the modules can be reloaded when
they are refreshed from perforce."""
def __init__(self):
self.previousModules = sys.modules.copy()
def rollbackImports(self):
# Assume that the scripts that are loaded from the scriptsRoot are not
# system modules.
scriptsRoot = utils.getScriptsRoot()
for modname in sys.modules.keys():
modfile = ''
if dir(sys.modules[modname]).count('__file__') != 0:
modfile = sys.modules[modname].__file__
log.debug('module name: '+modname+ ' checking if file: '+modfile+
' is under: '+scriptsRoot)
# We unload only those modules that are loaded from current root.
if modfile[0:len(scriptsRoot)] == scriptsRoot and \
not self.previousModules.has_key(modname):
log.debug('unloading module: %s', modname)
# Force reload when modname next imported
del(sys.modules[modname])
def isModuleLoaded(module):
return sys.modules.has_key(module)
def notifyKeyboardInterrupt():
"""Notify only if config is loaded. Helps testing."""
if isModuleLoaded('config'):
import config
if config.notifyKill:
import notify
notify.sendError("KeyboardInterrupt received: killed")
def notifySystemExit():
"""Notify only if config is loaded. Helps testing."""
if isModuleLoaded('config'):
import config
if config.notifyExit:
import notify
notify.sendError("SystemExit received: exited")
def notifyGlobalException():
"""Notify only if config is loaded. Helps testing."""
if isModuleLoaded('config'):
import notify
notify.sendError("Exception caught: " + str(sys.exc_info()[1]))
def getErrRestartDelay():
if isModuleLoaded('config'):
import config
return config.errRestartDelay
else:
return 1
class RunLoop((threading.Thread)):
def __init__(self, code='import runSched; runSched.runSched()'):
super(RunLoop, self).__init__()
self.setDaemon(True)
self.code = code
self.__rollbackImporter = None
def run(self):
while True:
if self.__rollbackImporter:
self.__rollbackImporter.rollbackImports()
self.__rollbackImporter = RollbackImporter()
try:
exec self.code
except utils.RestartProgram, ex:
log.info('Requst to reload modules received')
except KeyboardInterrupt:
log.info("Exiting via KeyboardInterrupt")
notifyKeyboardInterrupt()
sys.exit()
except SystemExit, ex:
log.info("Exiting via SystemExit")
notifySystemExit()
raise ex
except:
log.exception("Global exception handler")
time.sleep(getErrRestartDelay())
notifyGlobalException()
log.info("Reloading modules and restarting the loop...")
def test():
# Basic console logger.
rootLogger = logging.getLogger()
rootLogger.setLevel(logging.INFO)
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(logging.Formatter("%(message)s"))
rootLogger.addHandler(handler)
RunLoop('import testRunLoop; print "testValue="+str(testRunLoop.testValue); testRunLoop.restart()').start()
#RunLoop('import testRunLoop; print "testValue="+str(testRunLoop.testValue); sys.exit(0)').start()
#RunLoop('import testRunLoop; print "testValue="+str(testRunLoop.testValue); testRunLoop.raiseExcept()').start()
if __name__ == '__main__':
r = RunLoop()
r.start()
# Allows for KeyboardInterrupt to be generated in the main thread.
while r.isAlive():
r.join(1)