#******************************************************************** # # 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 win32serviceutil import win32service import win32event import win32api import win32evtlogutil import servicemanager import sys import time import logging log = logging.getLogger(__name__) # This is mostly based on the MyService.py sample code from py2exe project. # Handling custom configuration file is based on the ednasvc.py from edna # project (edna.sf.net). class P4AdminSvc(win32serviceutil.ServiceFramework): _svc_name_ = "P4AdminSvc" _svc_display_name_ = "p4admin service for p4Admin.py" _svc_deps_ = ["EventLog"] def __init__(self, args): win32serviceutil.ServiceFramework.__init__(self, args) self.hWaitStop = win32event.CreateEvent(None, 0, 0, None) self.configModName = win32serviceutil.GetServiceCustomOption(self, "ConfigurationFile") def reportevent(self, event, msg=''): try: win32evtlogutil.ReportEvent(self._svc_name_, event, 0, # category servicemanager.EVENTLOG_INFORMATION_TYPE, (self._svc_name_, '{'+msg+'}')) except win32api.error, ex: log.exception() def SvcStop(self): self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) win32event.SetEvent(self.hWaitStop) SvcShutdown = SvcStop def SvcDoRun(self): # Write a 'started' event to the event log... self.reportevent(servicemanager.PYS_SERVICE_STARTED, 'running with configuration file: '+str(self.configModName)) # Startup a separate thread to listen to stop event. This will allow us # to run the actual process in the main thread, matching the # command-line (handles SystemExit exception as expected). if self.configModName: sys.argv.append("--config") sys.argv.append(self.configModName) import p4admin # This will run the actual process in a separate thread. p4admin.RunLoop().start() # Wait for a few seconds such that config gets a chance to configure # logging (helps debugging). time.sleep(5) log.debug('%s: waiting for request to stop', self._svc_name_) while True: # wait for being stopped. r = win32event.WaitForSingleObject(self.hWaitStop, 5000) # Stop request received. if r == win32event.WAIT_OBJECT_0: self.reportevent(servicemanager.PYS_SERVICE_STOPPING, 'received request to stop') break elif r != win32event.WAIT_TIMEOUT: log.warning('%s: WaitForSingleObject returned invalid status: ' '%s', self._svc_name_, r) # Workaround for pywin32 bug, see user_config_template. if sys.modules.has_key('config'): import config if hasattr(config, 'workaroundPythonWin32ServiceAtexitBug') and \ config.workaroundPythonWin32ServiceAtexitBug: import atexit atexit._run_exitfuncs() # and write a 'stopped' event to the event log. self.reportevent(servicemanager.PYS_SERVICE_STOPPED) def customOptionHandler(opts): "This is only called when the service is installed. Configuration file is optional." for opt, val in opts: if opt == "-c": # This installs the location of the configuration file into: # HKLM\SYSTEM\CurrentControlSet\Services\\Parameters\ConfigurationFile win32serviceutil.SetServiceCustomOption(P4AdminSvc._svc_name_, "ConfigurationFile", val) if __name__ == '__main__': win32serviceutil.HandleCommandLine(P4AdminSvc, argv=sys.argv, customInstallOptions="c:", customOptionHandler=customOptionHandler)