[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