|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from __future__ import with_statement |
|
|
import contextlib |
|
|
import logging |
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
|
|
|
@contextlib.contextmanager |
|
|
def soffice_subprocess(**kwargs): |
|
|
''' Create an remote instance of soffice ''' |
|
|
|
|
|
args = [kwargs.get('soffice', 'soffice')] |
|
|
|
|
|
if 'accept' in kwargs: |
|
|
args.append('--accept=%s' % kwargs['accept']) |
|
|
|
|
|
if kwargs.get('headless', True): |
|
|
args.append('--headless') |
|
|
|
|
|
if kwargs.get('invisible', True): |
|
|
args.append('--invisible') |
|
|
|
|
|
if kwargs.get('nologo', True): |
|
|
args.append('--nologo') |
|
|
|
|
|
if kwargs.get('norestore', True): |
|
|
args.append('--norestore') |
|
|
|
|
|
if kwargs.get('nodefault', True): |
|
|
args.append('--nodefault') |
|
|
|
|
|
if kwargs.get('nofirstwizard', True): |
|
|
args.append('--nofirstwizard') |
|
|
|
|
|
import subprocess |
|
|
p = subprocess.Popen(args) |
|
|
pid = p.pid |
|
|
logger.info('soffice(%s) has been started.', pid) |
|
|
try: |
|
|
yield p |
|
|
finally: |
|
|
import time |
|
|
n = 0 |
|
|
p.poll() |
|
|
while p.returncode is None: |
|
|
n += 1 |
|
|
if n > 3: |
|
|
p.kill() |
|
|
logger.info('trying to kill soffice(%s)', pid) |
|
|
return |
|
|
p.terminate() |
|
|
time.sleep(1) |
|
|
p.poll() |
|
|
logger.info('soffice(%s) has been terminated with exit code %d', |
|
|
pid, p.returncode) |
|
|
|
|
|
|
|
|
def connect_remote_context(uno_link, max_tries=10): |
|
|
''' Connect to the remote soffice instance and get the context. ''' |
|
|
|
|
|
from unokit.services import css |
|
|
resolver = css.bridge.UnoUrlResolver() |
|
|
uno_url = 'uno:'+uno_link+'StarOffice.ComponentContext' |
|
|
logger.info('uno_url: %s', uno_url) |
|
|
from com.sun.star.connection import NoConnectException |
|
|
while True: |
|
|
max_tries -= 1 |
|
|
|
|
|
try: |
|
|
return resolver.resolve(uno_url) |
|
|
except NoConnectException, e: |
|
|
if max_tries <= 0: |
|
|
raise |
|
|
logger.info('%s - retrying', type(e).__name__) |
|
|
|
|
|
import time |
|
|
time.sleep(1) |
|
|
continue |
|
|
|
|
|
|
|
|
@contextlib.contextmanager |
|
|
def new_remote_context(pipe='oxt.tool', retry=3, make_current=True, **kwargs): |
|
|
''' Create a remote soffice instance and get its context |
|
|
|
|
|
:param pipe: connection pipe name |
|
|
:param retry: connect retry count; default True. |
|
|
:param make_current: whether the remote context would be pushed to be |
|
|
current context; default True. |
|
|
:param **kwargs: arguments to soffice_subprocess() |
|
|
:returns: remote context |
|
|
''' |
|
|
uno_link = 'pipe,name=%s;urp;' % pipe |
|
|
|
|
|
logger.debug('uno_link: %s', uno_link) |
|
|
|
|
|
kwargs['accept'] = uno_link |
|
|
while retry >= 0: |
|
|
with soffice_subprocess(**kwargs): |
|
|
import time |
|
|
time.sleep(1) |
|
|
try: |
|
|
context = connect_remote_context(uno_link, max_tries=10) |
|
|
except Exception, e: |
|
|
logger.exception(e) |
|
|
retry -= 1 |
|
|
continue |
|
|
|
|
|
if make_current: |
|
|
import unokit.contexts |
|
|
unokit.contexts.push(context) |
|
|
try: |
|
|
yield context |
|
|
finally: |
|
|
unokit.contexts.pop() |
|
|
else: |
|
|
yield context |
|
|
return |
|
|
|
|
|
|
|
|
class RemoteContextLayer: |
|
|
|
|
|
@classmethod |
|
|
def setUp(cls): |
|
|
cls.context = new_remote_context() |
|
|
cls.context.__enter__() |
|
|
|
|
|
@classmethod |
|
|
def tearDown(cls): |
|
|
cls.context.__exit__(None, None, None) |
|
|
|
|
|
|