diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3901713 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +__pycache__ +*.pyc + diff --git a/source/easymacro.py b/source/easymacro.py new file mode 100644 index 0000000..a817f99 --- /dev/null +++ b/source/easymacro.py @@ -0,0 +1,182 @@ +#!/usr/bin/env python3 + +# == Rapid Develop Macros in LibreOffice == + +# ~ https://git.cuates.net/elmau/easymacro + +# ~ easymacro 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 3 of the License, or +# ~ (at your option) any later version. + +# ~ easymacro 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 easymacro. If not, see . + + +import getpass +import logging +import os +import platform +import socket +import subprocess +import sys +import time + + +from typing import Any + + +import uno + +from com.sun.star.beans import PropertyValue + + +LOG_FORMAT = '%(asctime)s - %(levelname)s - %(message)s' +LOG_DATE = '%d/%m/%Y %H:%M:%S' +logging.addLevelName(logging.ERROR, '\033[1;41mERROR\033[1;0m') +logging.addLevelName(logging.DEBUG, '\x1b[33mDEBUG\033[1;0m') +logging.addLevelName(logging.INFO, '\x1b[32mINFO\033[1;0m') +logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT, datefmt=LOG_DATE) +log = logging.getLogger(__name__) + + +# Global variables +OS = platform.system() +DESKTOP = os.environ.get('DESKTOP_SESSION', '') +PC = platform.node() +USER = getpass.getuser() +IS_WIN = OS == 'Windows' +IS_MAC = OS == 'Darwin' +_info_debug = f"Python: {sys.version}\n\n{platform.platform()}\n\n" + '\n'.join(sys.path) + + +SALT = b'00a1bfb05353bb3fd8e7aa7fe5efdccc' + + +CTX = uno.getComponentContext() +SM = CTX.getServiceManager() + + +def debug(*args): + data = [str(a) for a in args] + log.debug('\t'.join(data)) + return + + +def error(info): + log.error(info) + return + + +def create_instance(name: str, with_context: bool=False, args: Any=None) -> Any: + if with_context: + instance = SM.createInstanceWithContext(name, CTX) + elif args: + instance = SM.createInstanceWithArguments(name, (args,)) + else: + instance = SM.createInstance(name) + return instance + + +def get_app_config(node_name: str, key: str='', update: bool=False): + name = 'com.sun.star.configuration.ConfigurationProvider' + service = 'com.sun.star.configuration.ConfigurationAccess' + if update: + service = 'com.sun.star.configuration.ConfigurationUpdateAccess' + cp = create_instance(name, True) + node = PropertyValue(Name='nodepath', Value=node_name) + try: + ca = cp.createInstanceWithArguments(service, (node,)) + if ca and not key: + return ca + if ca and ca.hasByName(key): + return ca.getPropertyValue(key) + except Exception as e: + error(e) + return '' + + +# Get info LibO +NAME = get_app_config('org.openoffice.Setup/Product', 'ooName') +VERSION = get_app_config('org.openoffice.Setup/Product','ooSetupVersion') +LANGUAGE = get_app_config('org.openoffice.Setup/L10N/', 'ooLocale') +LANG = LANGUAGE.split('-')[0] + + +INFO_DEBUG = f"{NAME} v{VERSION} {LANGUAGE}\n\n{_info_debug}" + + +class LOServer(object): + HOST = 'localhost' + PORT = '8100' + ARG = f'socket,host={HOST},port={PORT};urp;StarOffice.ComponentContext' + CMD = ['soffice', + '-env:SingleAppInstance=false', + '-env:UserInstallation=file:///tmp/LO_Process8100', + '--headless', '--norestore', '--invisible', + f'--accept={ARG}'] + + def __init__(self): + self._server = None + self._ctx = None + self._sm = None + self._start_server() + self._init_values() + + def _init_values(self): + global CTX + global SM + + if not self.is_running: + return + + ctx = uno.getComponentContext() + service = 'com.sun.star.bridge.UnoUrlResolver' + resolver = ctx.ServiceManager.createInstanceWithContext(service, ctx) + self._ctx = resolver.resolve('uno:{}'.format(self.ARG)) + self._sm = self._ctx.getServiceManager() + CTX = self._ctx + SM = self._sm + return + + @property + def is_running(self): + try: + s = socket.create_connection((self.HOST, self.PORT), 5.0) + s.close() + debug('LibreOffice is running...') + return True + except ConnectionRefusedError: + return False + + def _start_server(self): + if self.is_running: + return + + for i in range(3): + self._server = subprocess.Popen(self.CMD, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + time.sleep(3) + if self.is_running: + break + return + + def stop(self): + if self._server is None: + print('Search pgrep soffice') + else: + self._server.terminate() + debug('LibreOffice is stop...') + return + + def create_instance(self, name, with_context=True): + if with_context: + instance = self._sm.createInstanceWithContext(name, self._ctx) + else: + instance = self._sm.createInstance(name) + return instance diff --git a/source/test_config.py b/source/test_config.py new file mode 100644 index 0000000..1ab64b5 --- /dev/null +++ b/source/test_config.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 + +# Change values for your SO + +OS = 'Linux' +DESKTOP = 'gnome' +PC = 'oficina' +USER = 'mau' +IS_WIN = False +IS_MAC = False + +LIBO_VERSION = '7.3' +LANGUAGE = 'en-US' +LANG = 'en' diff --git a/source/test_easymacro.py b/source/test_easymacro.py new file mode 100644 index 0000000..59abdbf --- /dev/null +++ b/source/test_easymacro.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import unittest +import easymacro as app +from test_config import * + + +LIBO_NAME = 'LibreOffice' + + +class BaseTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + pass + + @classmethod + def tearDownClass(cls): + pass + + def setUp(self): + msg = f'In method: {self._testMethodName}' + app.debug(msg) + + # ~ @unittest.SkipTest + def tearDown(self): + pass + + +# ~ class TestDocuments(BaseTest): + + # ~ def test_new_doc(self): + # ~ result = app.new_doc() + # ~ self.assertIsInstance(result, app.LOCalc) + # ~ result.close() + + # ~ def test_get_type_doc(self): + # ~ expected = 'calc' + # ~ result = app.new_doc() + # ~ self.assertEqual(result.type, expected) + # ~ result.close() + + +class TestVars(BaseTest): + + def test_01_os(self): + expected = OS + result = app.OS + self.assertEqual(result, expected) + + def test_02_desktop(self): + expected = DESKTOP + result = app.DESKTOP + self.assertEqual(result, expected) + + def test_03_pc(self): + expected = PC + result = app.PC + self.assertEqual(result, expected) + + def test_04_user(self): + expected = USER + result = app.USER + self.assertEqual(result, expected) + + def test_05_is_win(self): + expected = IS_WIN + result = app.IS_WIN + self.assertEqual(result, expected) + + def test_06_is_mac(self): + expected = IS_MAC + result = app.IS_MAC + self.assertEqual(result, expected) + + def test_07_name(self): + expected = LIBO_NAME + result = app.NAME + self.assertEqual(result, expected) + + def test_08_version(self): + expected = LIBO_VERSION + result = app.VERSION + self.assertEqual(result, expected) + + def test_09_language(self): + expected = LANGUAGE + result = app.LANGUAGE + self.assertEqual(result, expected) + + def test_10_lang(self): + expected = LANG + result = app.LANG + self.assertEqual(result, expected) + + +# ~ class TestTools(BaseTest): + + # ~ def test_create_instance_not_exists(self): + # ~ result = app.create_instance('no.exists.zaz') + # ~ self.assertIsNone(result) + + # ~ def test_create_instance(self): + # ~ result = app.create_instance('com.sun.star.frame.Desktop') + # ~ self.assertIsNotNone(result) + + # ~ def test_set_get_config(self): + # ~ expected = 'TEST' + # ~ result = app.set_config('test', 'TEST', 'test') + # ~ self.assertTrue(result) + # ~ result = app.get_config('test', '', 'test') + # ~ self.assertEqual(result, expected) + + +if __name__ == '__main__': + server = app.LOServer() + unittest.main(exit=False) + server.stop()