[Erp5-report] r15722 - /erp5/trunk/utils/oood/
nobody at svn.erp5.org
nobody at svn.erp5.org
Fri Aug 17 11:58:46 CEST 2007
Author: jerome
Date: Fri Aug 17 11:58:46 2007
New Revision: 15722
URL: http://svn.erp5.org?rev=15722&view=rev
Log:
Support for running under windows platorm, by Klaus Wölfel
Added:
erp5/trunk/utils/oood/winservice.py
Modified:
erp5/trunk/utils/oood/config.py
erp5/trunk/utils/oood/dispatcher.py
erp5/trunk/utils/oood/start.py
erp5/trunk/utils/oood/testOoodBasicOperations.py
Modified: erp5/trunk/utils/oood/config.py
URL: http://svn.erp5.org/erp5/trunk/utils/oood/config.py?rev=15722&r1=15721&r2=15722&view=diff
==============================================================================
--- erp5/trunk/utils/oood/config.py (original)
+++ erp5/trunk/utils/oood/config.py Fri Aug 17 11:58:46 2007
@@ -28,11 +28,20 @@
#
##############################################################################
+import os
import logging
from ConfigParser import ConfigParser
+WIN = False
+if os.name == 'nt':
+ WIN = True
+
config = ConfigParser()
-config.read(['/etc/oood/oood.conf', 'oood.conf'])
+
+if WIN:
+ config.read([r'C:\ERP5\oood\oood.conf'])
+else:
+ config.read(['/etc/oood/oood.conf', 'oood.conf'])
###################################################################
# System config
Modified: erp5/trunk/utils/oood/dispatcher.py
URL: http://svn.erp5.org/erp5/trunk/utils/oood/dispatcher.py?rev=15722&r1=15721&r2=15722&view=diff
==============================================================================
--- erp5/trunk/utils/oood/dispatcher.py (original)
+++ erp5/trunk/utils/oood/dispatcher.py Fri Aug 17 11:58:46 2007
@@ -385,7 +385,7 @@
# we have to store in a file for OOo to open
filename = '%d_%s' % (worker.idx, lib.asciify(kw['filename'])) # prepend worker index in case we have two files of the same name
filename = self._mkName(filename)
- f = open(filename, 'w')
+ f = open(filename, 'wb')
try:
f.write(kw['data'])
finally:
@@ -404,7 +404,7 @@
if tozip:
self._zipResult(kw)
else:
- f = open(self._mkName(kw['newfilename']))
+ f = open(self._mkName(kw['newfilename']), 'rb')
try:
kw['data'] = f.read()
finally:
Modified: erp5/trunk/utils/oood/start.py
URL: http://svn.erp5.org/erp5/trunk/utils/oood/start.py?rev=15722&r1=15721&r2=15722&view=diff
==============================================================================
--- erp5/trunk/utils/oood/start.py (original)
+++ erp5/trunk/utils/oood/start.py Fri Aug 17 11:58:46 2007
@@ -43,7 +43,11 @@
import config
from logger import Log
-
+WIN = False
+if os.name == 'nt':
+ WIN = True
+ from subprocess import Popen, PIPE
+ import winservice as winutils
"""
Size of the pool is defined in config under the 'pool_size' parameter.
@@ -70,7 +74,10 @@
"""
_l("Starting...", i)
instance_port = config.pool_port_range_start + i
- BIN = "soffice"
+ if WIN:
+ BIN = "soffice.exe"
+ else:
+ BIN = "soffice"
cmd = '%s/%s' % (config.uno_path, BIN)
# "'-display :%d' % config.virtual_display_id" argument is not working, that's why we use
# environnment variable. See "man xhost" for more details.
@@ -94,7 +101,12 @@
(config.run_dir.strip('/'),i)
, new_context
]
- pid = os.spawnlpe(os.P_NOWAIT, cmd, *args_and_env)
+ if WIN:
+ cmd_and_args = [cmd] + args_and_env[1:-1]
+ process = Popen(cmd_and_args)
+ pid = process.pid
+ else:
+ pid = os.spawnlpe(os.P_NOWAIT, cmd, *args_and_env)
_l("Listening at %s:%s" % (config.pool_host, instance_port), i)
pidfile = os.path.join(config.run_dir, 'instance_%d.pid' % i)
open(pidfile, 'w').write(str(pid))
@@ -104,12 +116,15 @@
# otherwise when it is killed it becomes a zombie
# so we establish a waiting thread, not to block the whole process
_l("Starting waiting thread for process %s" % pid, i)
- waiting_thread = threading.Thread(target=justWait, args=(pid,))
+ if WIN:
+ waiting_thread = threading.Thread(target=justWait, args=(process._handle,))
+ else:
+ waiting_thread = threading.Thread(target=justWait, args=(pid,))
waiting_thread.start()
_l("Started as process %s" % pid, i)
def justWait(pid):
- os.waitpid(pid, 0)
+ os.waitpid(pid, 0)
def killInstance(i):
_l("Kill requested", i)
@@ -119,20 +134,30 @@
instance_master_pid = int(pid_file.read())
pid_file.close()
# OOo instance span on several process, find all of them
- pid_list = os.popen('ps -A -o pid,ppid').read().split('\n')
- instance_pid_list = []
- for pid_line in pid_list:
- pid_pair = re.findall('(\d+)', pid_line)
- if len(pid_pair) == 2:
- pid_pair = [int(pid) for pid in pid_pair]
- if instance_master_pid in pid_pair:
- instance_pid_list.append(pid_pair[0])
+ # on windows this is not necessary because the supprocesses
+ # are automatically terminated when we kill the OOo parent process
+ if WIN:
+ instance_pid_list = winutils.getChildrenOfPid(instance_master_pid)
+ if instance_pid_list:
+ instance_pid_list.append(instance_master_pid)
+ else:
+ pid_list = os.popen('ps -A -o pid,ppid').read().split('\n')
+ instance_pid_list = []
+ for pid_line in pid_list:
+ pid_pair = re.findall('(\d+)', pid_line)
+ if len(pid_pair) == 2:
+ pid_pair = [int(pid) for pid in pid_pair]
+ if instance_master_pid in pid_pair:
+ instance_pid_list.append(pid_pair[0])
if len(instance_pid_list) > 0:
_l("Is still running and span on several processes: %s" % ', '.join([str(x) for x in instance_pid_list]), i)
# Kill all instance processes
for pid in instance_pid_list:
_l("Killing process %s..." % pid, i)
- os.kill(pid, 9)
+ if WIN:
+ winutils.SafeTerminateProcess(pid)
+ else:
+ os.kill(pid, 9)
_l("Killed", i)
else:
_l("Was not properly shutdown", i)
@@ -305,7 +330,8 @@
sys.exit(0)
elif o in ("-f", "--flush"):
flushPool()
- killVirtualFrameBuffer()
+ if not WIN:
+ killVirtualFrameBuffer()
sys.exit(0)
elif o in ("-s", "--status", "--stat"):
showPoolStatus()
Modified: erp5/trunk/utils/oood/testOoodBasicOperations.py
URL: http://svn.erp5.org/erp5/trunk/utils/oood/testOoodBasicOperations.py?rev=15722&r1=15721&r2=15722&view=diff
==============================================================================
--- erp5/trunk/utils/oood/testOoodBasicOperations.py (original)
+++ erp5/trunk/utils/oood/testOoodBasicOperations.py Fri Aug 17 11:58:46 2007
@@ -69,7 +69,7 @@
print host
try:
- f = open('%s/test.odt' % doc_dir)
+ f = open('%s/test.odt' % doc_dir, 'rb')
except IOError:
print "you need a %s subdir with appropriate documents" % doc_dir
sys.exit(1)
@@ -85,13 +85,13 @@
# setting metadata
mime = 'application/vnd.oasis.opendocument.text'
newmeta = {'title':'HELLOOOOOO', 'reference':'blaaaaaah', 'MIMEType':mime}
- data = open(doc_dir+'/test.odt').read()
+ data = open(doc_dir+'/test.odt','rb').read()
res = sp.setmetadata('test.odt', base64.encodestring(data), newmeta)
res = responseFactory(res)
self.failUnless(res.isOk())
- open(doc_dir+'/out/test_changed.odt', 'w').write(res.data)
+ open(doc_dir+'/out/test_changed.odt', 'wb').write(res.data)
# getting metadata back after the change
- data = open(doc_dir+'/out/test_changed.odt').read()
+ data = open(doc_dir+'/out/test_changed.odt','rb').read()
res = sp.getmetadata('test_changed.odt', base64.encodestring(data))
res = responseFactory(res)
self.failUnless(res.isOk())
@@ -104,12 +104,12 @@
"""
This test passes arguments the old way.
"""
- data = open(doc_dir+'/test.doc').read()
+ data = open(doc_dir+'/test.doc', 'rb').read()
res = sp.convert('test.doc', base64.encodestring(data))
res = responseFactory(res)
self.failUnless(res.isOk())
self.assertEqual(res.mime, 'application/vnd.oasis.opendocument.text')
- open(doc_dir+'/out/test.odt', 'w').write(res.data)
+ open(doc_dir+'/out/test.odt', 'wb').write(res.data)
res = sp.getAllowedTargetItemList(res.mime)
res = responseFactory(res)
self.failUnless(res.isOk())
@@ -120,13 +120,13 @@
"""
This test uses Request object with constructor.
"""
- data = open(doc_dir+'/test.xls').read()
+ data = open(doc_dir+'/test.xls', 'rb').read()
request = Request(filename='text.xls', data=data)
res = sp.convert(request)
res = responseFactory(res)
self.failUnless(res.isOk())
self.assertEqual(res.mime, 'application/vnd.oasis.opendocument.spreadsheet')
- open(doc_dir+'/out/test.ods', 'w').write(res.data)
+ open(doc_dir+'/out/test.ods', 'wb').write(res.data)
request = Request(mimetype=res.mime)
res = sp.getAllowedTargetItemList(request)
res = responseFactory(res)
@@ -138,7 +138,7 @@
"""
This test uses Request object setting attributes.
"""
- data = open(doc_dir+'/test.ppt').read()
+ data = open(doc_dir+'/test.ppt', 'rb').read()
request = Request()
request.filename = 'test.ppt'
request.data = data
@@ -146,7 +146,7 @@
res = responseFactory(res)
self.failUnless(res.isOk())
self.assertEqual(res.mime,'application/vnd.oasis.opendocument.presentation')
- open(doc_dir+'/out/test.odp', 'w').write(res.data)
+ open(doc_dir+'/out/test.odp', 'wb').write(res.data)
request = Request()
request.mimetype = res.mime
res = sp.getAllowedTargetItemList(request)
@@ -156,21 +156,21 @@
self.failUnless('impr.pdf' in extractExtensions(target_list))
def testPdfTextGeneration(self):
- data = open(doc_dir+'/test.odt').read()
+ data = open(doc_dir+'/test.odt', 'rb').read()
request = Request(filename='test.odt', data=data, extension='pdf')
res = sp.generate(request)
self.assert_(res)
res = responseFactory(res)
self.failUnless(res.isOk())
self.assertEqual(res.mime, 'application/pdf')
- open(doc_dir+'/out/test.pdf', 'w').write(res.data)
+ open(doc_dir+'/out/test.pdf', 'wb').write(res.data)
def testPdfTextGenerationWithIllegalChars(self):
"""
This tries to break xmlrpc protocol by putting illegal character in filename
(the Request class should fix it before proceeding).
"""
- data = open(doc_dir+'/test.odt').read()
+ data = open(doc_dir+'/test.odt', 'rb').read()
request = Request(filename='tê¿yci±¿y.odt', data=data, extension='pdf')
res = sp.generate(request)
self.assert_(res)
@@ -180,7 +180,7 @@
If filename was not given in the request, the server should produce its own
from random digits.
"""
- data = open(doc_dir+'/test.odt').read()
+ data = open(doc_dir+'/test.odt', 'rb').read()
request = Request(data=data, extension='pdf')
res = sp.generate(request)
self.assert_(res)
@@ -189,22 +189,22 @@
self.failUnless(re.match('.*\d{2}$', res.filename))
def testPdfCalcGeneration(self):
- data = open(doc_dir+'/test.ods').read()
+ data = open(doc_dir+'/test.ods', 'rb').read()
res = sp.generate('test.ods', enc(data), -1, 'calc.pdf')
self.assert_(res)
res = responseFactory(res)
self.failUnless(res.isOk())
self.assertEqual(res.mime, 'application/pdf')
- open(doc_dir+'/out/test.calc.pdf', 'w').write(res.data)
+ open(doc_dir+'/out/test.calc.pdf', 'wb').write(res.data)
def testPdfImpressGeneration(self):
- data = open(doc_dir+'/test.odp').read()
+ data = open(doc_dir+'/test.odp', 'rb').read()
res = sp.generate('test.odp', enc(data), -1, 'impr.pdf')
self.assert_(res)
res = responseFactory(res)
self.failUnless(res.isOk())
self.assertEqual(res.mime, 'application/pdf')
- open(doc_dir+'/out/test.impr.pdf', 'w').write(res.data)
+ open(doc_dir+'/out/test.impr.pdf', 'wb').write(res.data)
def testHtmlWriterGeneration(self):
self.generateFile('odt', 'writer.html')
@@ -237,22 +237,22 @@
self.generateFile('doc', 'txt')
def testDocFromTxtGeneration(self):
- data = open(doc_dir+'/test.iso.txt').read()
+ data = open(doc_dir+'/test.iso.txt', 'rb').read()
request = Request(filename='test.iso.txt', data=data, extension='doc')
res = sp.generate(request)
self.assert_(res)
res = responseFactory(res)
self.failUnless(res.isOk())
- open(doc_dir+'/out/test.iso.doc', 'w').write(res.data)
+ open(doc_dir+'/out/test.iso.doc', 'wb').write(res.data)
def generateFile(self,src,ext):
- data = open(doc_dir+'/test.%s' % src).read()
+ data = open(doc_dir+'/test.%s' % src, 'rb').read()
request = Request(filename='test.%s' % src, data=data, extension=ext)
res = sp.generate(request)
self.assert_(res)
res = responseFactory(res)
self.failUnless(res.isOk())
- open(doc_dir+'/out/test.%s' % ext, 'w').write(res.data)
+ open(doc_dir+'/out/test.%s' % ext, 'wb').write(res.data)
if __name__=='__main__':
tests=(TestMetaOperations, TestFileOperations)
Added: erp5/trunk/utils/oood/winservice.py
URL: http://svn.erp5.org/erp5/trunk/utils/oood/winservice.py?rev=15722&view=auto
==============================================================================
--- erp5/trunk/utils/oood/winservice.py (added)
+++ erp5/trunk/utils/oood/winservice.py Fri Aug 17 11:58:46 2007
@@ -1,0 +1,124 @@
+##############################################################################
+#
+# Copyright (c) 2002, 2007 Nexedi SA and Contributors. All Rights Reserved.
+# Klaus Woelfel
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# 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 2
+# 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+##############################################################################
+
+import os
+import sys
+import socket
+import start
+import config
+import pywintypes
+import win32api
+import win32con
+import win32process
+import win32event
+import win32service
+import win32serviceutil
+import win32com.client
+from time import sleep
+from logger import Log
+from dispatcher import Dispatcher, MySerw
+
+class ooodService(win32serviceutil.ServiceFramework):
+ _svc_name_ = 'oood'
+ _svc_display_name_ = 'oood'
+ _svc_description_ = ('A server for converting docs from other formats to '
+ 'OOo, generating pdf files, getting and setting '
+ 'metadata. To be used together with ERP5.')
+ _exe_name_ = r'C:\Programme\Office\OpenOffice.org.2.0\program\python-core-2.3.4\lib\site-packages\win32\pythonservice.exe'
+
+ def __init__(self, args):
+ # set the timeout so the service can stop...Otherwise it hangs forever
+ socket.setdefaulttimeout(15)
+ win32serviceutil.ServiceFramework.__init__(self, args)
+ self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
+
+ def SvcStop(self):
+ self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
+ win32event.SetEvent(self.hWaitStop)
+
+ def SvcDoRun(self):
+ if not os.access(os.path.join(config.oood_home, 'tmp'), os.W_OK):
+ message = 'ERROR: A tmp subdirectory must exist and must be writeable!!!'
+ Log.info(message)
+ return
+ message = "Server - Started as Windows Service"
+ Log.info(message)
+ # Start the server core
+ disp = Dispatcher()
+ server_port = config.server_port
+ ser = MySerw((config.server_host, server_port))
+ ser.register_instance(disp)
+ # handle requests until Service is stopped
+ while True:
+ rc = win32event.WaitForSingleObject(self.hWaitStop, 0)
+ if rc == win32event.WAIT_TIMEOUT:
+ ser.handle_request()
+ else:
+ # kill OpenOffice insatnces
+ start.flushPool()
+ break
+
+def getChildrenOfPid(pid):
+ wmi = win32com.client.GetObject('winmgmts:')
+ children = wmi.ExecQuery('Select * from win32_process where ParentProcessId=%s' % pid)
+ pids = []
+ for proc in children:
+ pids.append(int(proc.Properties_('ProcessId')))
+ return pids
+
+def SafeTerminateProcess(pid, timeout=5000):
+ success = False
+ # if opening the handle failed, than the process is already killed and
+ # we return success also we did nothing
+ try:
+ handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, False, pid)
+ except pywintypes.error, e:
+ if e[0] == 87:
+ return success
+ else:
+ raise
+
+ exitcode = win32process.GetExitCodeProcess(handle)
+ if exitcode == win32con.STILL_ACTIVE:
+ hKernel = win32api.GetModuleHandle("Kernel32")
+ procExit = win32api.GetProcAddress(hKernel, "ExitProcess")
+ hRemoteT = win32process.CreateRemoteThread(handle, None, 0, procExit, -1, 0)
+ # waiting after starting remote thread
+ retval = win32event.WaitForSingleObject(handle, timeout)
+ # if timeout elapsed, we can't guarantee that the process is dead
+ if retval != win32con.WAIT_TIMEOUT:
+ success = True
+ #win32api.CloseHandle(hRemoteT) #doesn't work at the moment
+ else:
+ # the process was already dead
+ success = True
+ win32api.CloseHandle(handle)
+ return success
+
+if __name__=='__main__':
+ win32serviceutil.HandleCommandLine(ooodService)
More information about the Erp5-report
mailing list