1 # -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*-
3 # This Source Code Form is subject to the terms of the Mozilla Public
4 # License, v. 2.0. If a copy of the MPL was not distributed with this
5 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
20 print("pyuno not found: try to set PYTHONPATH and URE_BOOTSTRAP variables", flush
=True)
21 print("PYTHONPATH=/installation/opt/program", flush
=True)
22 print("URE_BOOTSTRAP=file:///installation/opt/program/fundamentalrc", flush
=True)
25 def signal_handler(signal_num
, frame
):
26 signal_name
= signal
.Signals(signal_num
).name
27 #print(f'Signal handler called with signal {signal_name} ({signal_num})', flush=True)
29 class OfficeConnection
:
30 def __init__(self
, args
):
36 """ Create a new connection to a LibreOffice process
38 If the connection method is path the instance will be created as a
39 new subprocess. If the connection method is connect the instance tries
40 to connect to an existing instance with the specified socket string """
41 if platform
.system() != "Windows":
42 signal
.signal(signal
.SIGCHLD
, signal_handler
)
43 signal
.signal(signal
.SIGPIPE
, signal_handler
)
45 (method
, sep
, rest
) = self
.args
["--soffice"].partition(":")
47 raise Exception("soffice parameter does not specify method")
49 socket
= "pipe,name=pytest" + str(uuid
.uuid1())
51 userdir
= self
.args
["--userdir"]
53 raise Exception("'path' method requires --userdir")
54 if not(userdir
.startswith("file://")):
55 raise Exception("--userdir must be file URL")
56 self
.soffice
= self
.bootstrap(rest
, userdir
, socket
)
57 elif method
== "connect":
60 raise Exception("unsupported connection method: " + method
)
62 # connect to the soffice instance
65 self
.xContext
= self
.connect(socket
)
68 if not success
and self
.soffice
:
69 self
.soffice
.terminate()
73 def bootstrap(self
, soffice
, userdir
, socket
):
74 """ Creates a new LibreOffice process
76 @param soffice Path to the soffice installation
77 @param userdir Directory of the user profile, only one process per user
79 @param socket The socket string used for the PyUNO connection """
81 argv
= [soffice
, "--accept=" + socket
+ ";urp",
82 "-env:UserInstallation=" + userdir
,
83 "--quickstart=no", "--nofirststartwizard",
84 "--norestore", "--nologo"]
85 if "--valgrind" in self
.args
:
86 argv
.append("--valgrind")
88 if "--gdb" in self
.args
:
92 argv
.insert(3, "--args")
93 argv
[4] = argv
[4].replace("soffice", "soffice.bin")
96 environ
= dict(os
.environ
)
97 if 'LIBO_LANG' in environ
:
99 env
['LC_ALL'] = environ
['LIBO_LANG']
101 return subprocess
.Popen(argv
, env
=env
)
103 def connect(self
, socket
):
104 """ Tries to connect to the LibreOffice instance through the specified socket"""
105 xLocalContext
= uno
.getComponentContext()
106 xUnoResolver
= xLocalContext
.ServiceManager
.createInstanceWithContext(
107 "com.sun.star.bridge.UnoUrlResolver", xLocalContext
)
108 url
= "uno:" + socket
+ ";urp;StarOffice.ComponentContext"
109 print("OfficeConnection: connecting to: " + url
, flush
=True)
111 if self
.soffice
and self
.soffice
.poll() is not None:
112 raise Exception("soffice has stopped.")
115 xContext
= xUnoResolver
.resolve(url
)
117 except pyuno
.getClass("com.sun.star.connection.NoConnectException"):
118 print("NoConnectException: sleeping...", flush
=True)
122 """Terminate a LibreOffice instance created with the path connection method.
124 Tries to terminate the soffice instance through the normal
125 XDesktop::terminate method and waits indefinitely for the subprocess
131 print("tearDown: calling terminate()...", flush
=True)
132 xMgr
= self
.xContext
.ServiceManager
133 xDesktop
= xMgr
.createInstanceWithContext(
134 "com.sun.star.frame.Desktop", self
.xContext
)
136 print("...done", flush
=True)
137 except pyuno
.getClass("com.sun.star.beans.UnknownPropertyException"):
138 print("caught while TearDown:\n", traceback
.format_exc(), flush
=True)
139 pass # ignore, also means disposed
140 except pyuno
.getClass("com.sun.star.lang.DisposedException"):
141 print("caught while TearDown:\n", traceback
.format_exc(), flush
=True)
144 self
.soffice
.terminate()
146 ret
= self
.soffice
.wait()
150 raise Exception("Exit status indicates failure: " + str(ret
))
153 def getHelpText(cls
):
155 --soffice=method:location
156 specify soffice instance to connect to
157 supported methods: 'path', 'connect'
158 --userdir=URL specify user installation directory for 'path' method
159 --valgrind pass --valgrind to soffice for 'path' method
161 'location' is a pathname, not a URL. 'userdir' is a URL.
166 class PersistentConnection
:
167 def __init__(self
, args
):
169 self
.connection
= None
171 def getContext(self
):
172 """ Returns the XContext corresponding to the LibreOffice instance
174 This is the starting point for any PyUNO access to the LibreOffice
176 return self
.connection
.xContext
179 # don't create two connections
183 conn
= OfficeConnection(self
.args
)
185 self
.connection
= conn
190 self
.connection
.tearDown()
192 self
.connection
= None
195 """ Kills the LibreOffice instance if it was created through the connection
197 Only works with the connection method path"""
198 if self
.connection
and self
.connection
.soffice
:
199 self
.connection
.soffice
.kill()
201 # vim: set shiftwidth=4 softtabstop=4 expandtab: