#********************************************************************
#
# 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\<svcname>\Parameters\ConfigurationFile
win32serviceutil.SetServiceCustomOption(P4AdminSvc._svc_name_,
"ConfigurationFile", val)
if __name__ == '__main__':
win32serviceutil.HandleCommandLine(P4AdminSvc, argv=sys.argv,
customInstallOptions="c:", customOptionHandler=customOptionHandler)