1 # -*- mode: python ; coding: utf-8 -*-
3 # Copyright (c) 2008 by Hartmut Goebel <h.goebel@goebel-consult.de>
4 # Licenced under the GNU General Public License v3 (GPLv3)
5 # see file LICENSE-gpl-3.0.txt
7 # Originally based on officehelper.py 1.2 comming with OOo
10 __author__ = "Hartmut Goebel <h.goebel@goebel-consult.de>"
11 __copyright__ = "Copyright (c) 2008 by Hartmut Goebel <h.goebel@goebel-consult.de>"
12 __licence__ = "GPLv3 - GNU General Public License v3"
17 from time import sleep
20 from com.sun.star.connection import NoConnectException
22 class BootstrapException(Exception): pass
24 __soffice_executable = None
26 def _build_connect_string(pipename=None, host=None, port=None):
28 Returns a connection description string to be used to connect to
29 this process via UnoUrlResolver().resolve().
31 Pass either a pipename for a named pipe or host and port for a
34 Note: You should use the naemd pipe whenever possible, since
35 socket are unsecure: Everybody can connect to a socket and access
36 your documents without any access control.
39 connectString = "pipe,name=%s" % pipename
41 connectString = 'socket'
42 if host: connectString += ',host='+str(host)
43 if port: connectString += ',port='+str(port)
47 def _build_cmd_args(connectString, unaccept=False):
49 Returns command arguments (including executable and options)
50 suitable for staring an background OOo instance listening on named
51 pipe or socket descripted in parameter 'connectString'.
53 If unaccept is true, the parmeter '-accept=...' will become
54 '-unaccept=...' for making the instance unlisten.
57 def find_executable():
59 Find 'soffice' executable.
61 Normaly soffice should be in the same directory as uno.py, but eg.
62 Debian does not obaj to this convention. Thus we need to search
65 global __soffice_executable
66 if __soffice_executable:
67 return __soffice_executable
68 for p in [os.path.dirname(uno.__file__),
69 '/opt/libreoffice/program',
70 '/usr/lib/libreoffice/program',
71 '/usr/lib/openoffice/program',
72 '/usr/lib/ooo/program',
76 office = os.path.join(p, "soffice")
77 if os.path.exists(office):
81 pathes = glob.glob('/usr/lib/ooo-[234].*/program/soffice')
83 raise BootstrapExceptions('soffice executable not found')
84 pathes.sort(reverse=True)
86 __soffice_executable = office
89 # soffice script used on *ix, Mac; soffice.exe used on Windoof
90 office = find_executable()
91 if sys.platform.startswith("win"):
94 # -headless includes -invisible (which includes -nologo -nodefault)
95 accept = unaccept and '-unaccept' or '-accept'
97 "-headless", "-norestore", "%s=%s;urp;" %
98 (accept, connectString))
102 def _start_OOo(connectString):
103 """Start an OOo process listening on named pipe or socket
104 descripted in parameter 'connectString'.
106 cmdArray = _build_cmd_args(connectString)
107 # Start the office proces, don't check for exit status since
108 # an exception is caught anyway if the office terminates
110 return os.spawnv(os.P_NOWAIT, cmdArray[0], cmdArray)
113 def connect(connectString):
115 Connect to an OOo instance listening on named pipe or socket
116 descripted in parameter 'connectString'.
118 localContext = uno.getComponentContext()
119 resolver = localContext.ServiceManager.createInstanceWithContext(
120 "com.sun.star.bridge.UnoUrlResolver", localContext)
121 connect = "uno:" + connectString + ";urp;StarOffice.ComponentContext"
123 # Wait until an office is started, but loop only 20 times (10 seconds)
126 context = resolver.resolve(connect)
128 except NoConnectException:
129 sleep(0.5) # Sleep 1/2 second.
131 # for-loop completed without 'break' (this is: no connection found)
132 raise BootstrapException("Cannot connect to soffice server.")
137 def bootstrap(pipename=None, host=None, port=None):
138 """Bootstrap OOo and PyUNO Runtime.
140 If either pipename, host or port are given, connect to the OOo
141 instance listening on this pipe or hosst/port. (This is mainly for
142 convenience, so programms do not need to distinguish these cases.)
144 If non of these parameters are give, the soffice process is
145 started opening a named pipe of random name, then the local
146 context is used to access the pipe.
148 This function directly returns the remote component context, from
149 whereon you can get the ServiceManager by calling
150 getServiceManager() on the returned object.
152 if pipename or host or port:
153 connectString = _build_connect_string(pipename=pipename,
154 host=host, port=port)
156 # Generate a random pipe name.
157 pipename = "uno" + str(random.random())[2:]
158 connectString = _build_connect_string(pipename=pipename)
159 # start OOo listening on this named pipe
160 _start_OOo(connectString)
161 # get component context and return it
162 context = connect(connectString)