diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..58bd977
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,14 @@
+__pycache__/
+*.py[cod]
+
+*.log
+conf.py
+files/
+
+docs/
+
+# Virtualenv
+.env/
+virtual/
+
+
diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644
index 0000000..155a043
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,4 @@
+v 0.1.0 [06-sep-2019]
+---------------------
+ - Initial version
+
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..45e2060
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,17 @@
+* Used zaz and easymacro
+* Report errors
+* Add examples
+* Add to list of proyects develop with zaz or easymacro
+* Send me a postal card
+* Pay for support
+
+
+**BCH**: `pzkuydh70v4r52hl3nqs66gy9wqdtrgej5ewv48xyq`
+
+**BTC**: `3FhiXcXmAesmQzrNEngjHFnvaJRhU1AGWV`
+
+**LTC**: `MBcgQ3LQJA4W2wsXknTdm2fxRSysLaBJHS`
+
+**ETH**: `0x61a4f614a30ff686445751ed8328b82b77ecfc69`
+
+
diff --git a/README.md b/README.md
index 8eca20b..7993ed5 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,7 @@
ZAZ
Scripts and library for develop macros in LibreOffice with Python.
+
+Develop in pure Python, not need any dependence.
+
+For Python 3.6+
diff --git a/TODO.md b/TODO.md
new file mode 100644
index 0000000..d294d43
--- /dev/null
+++ b/TODO.md
@@ -0,0 +1,5 @@
+* Automatic update
+* Help
+* Configuration
+* Option panel
+* Sub-menus
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..f3e862a
--- /dev/null
+++ b/VERSION
@@ -0,0 +1,2 @@
+zaz 0.1.0
+easymacro 0.1.0
diff --git a/source/conf.py.example b/source/conf.py.example
new file mode 100644
index 0000000..13b19b8
--- /dev/null
+++ b/source/conf.py.example
@@ -0,0 +1,541 @@
+# ~ This file is part of ZAZ.
+
+# ~ ZAZ 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.
+
+# ~ ZAZ 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 ZAZ. If not, see .
+
+
+import logging
+
+
+# ~ Type extension:
+# ~ 1 = normal extension
+# ~ 2 = new component
+# ~ 3 = Calc addin
+TYPE_EXTENSION = 1
+
+# ~ https://semver.org/
+VERSION = '0.1.0'
+
+# ~ Your great extension name, not used spaces
+NAME = 'TestMacro'
+
+# ~ Should be unique, used URL inverse
+ID = 'org.myextension.test'
+
+PUBLISHER = {
+ 'en': {'text': 'El Mau', 'link': 'https://elmau.net'},
+ 'es': {'text': 'El Mau', 'link': 'https://elmau.net'},
+}
+
+# ~ Name in this folder for copy
+ICON = 'images/logo.png'
+# ~ Name inside extensions
+ICON_EXT = f'{NAME.lower()}.png'
+
+# ~ For example
+# ~ DEPENDENCIES_MINIMAL = '6.0'
+DEPENDENCIES_MINIMAL = ''
+
+LICENSE_ACCEPT_BY = 'user' # or admin
+LICENSE_SUPPRESS_ON_UPDATE = True
+# ~ Change for you favorite license
+LICENSE_EN = f"""This file is part of {NAME}.
+
+ {NAME} 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.
+
+ {NAME} 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 {NAME}. If not, see .
+"""
+LICENSE_ES = LICENSE_EN
+
+INFO = {
+ 'en': {
+ 'display_name': 'Test Macro',
+ 'description': 'My great extension',
+ 'license': LICENSE_EN,
+ },
+ 'es': {
+ 'display_name': 'Macro de Prueba',
+ 'description': 'Mi gran extensión',
+ 'license': LICENSE_ES,
+ },
+}
+
+
+CONTEXT = {
+ 'calc': 'com.sun.star.sheet.SpreadsheetDocument',
+}
+
+
+# ~ Menus, only for TYPE_EXTENSION = 1
+# ~ Parent can be: AddonMenu or OfficeMenuBar
+# ~ For icons con name: NAME_16.bmp, used only NAME
+# ~ PARENT = 'AddonMenu'
+# ~ MENU_MAIN = ''
+PARENT = 'OfficeMenuBar'
+MENU_MAIN = {
+ 'en': 'My Extension',
+ 'es': 'Mi Extensión',
+}
+MENUS = (
+ {
+ 'title': {'en': 'Option 1', 'es': 'Opción 1'},
+ 'argument': 'option1',
+ 'context': '',
+ 'icon': 'icon',
+ 'toolbar': True,
+ },
+)
+
+# ~ Functions, only for TYPE_EXTENSION = 3
+FUNCTIONS = {
+ 'test': {
+ 'displayname': {'en': 'test', 'es': 'prueba'},
+ 'description': {'en': 'My test', 'es': 'Mi prueba'},
+ 'parameters': {
+ 'value': {
+ 'displayname': {'en': 'value', 'es': 'valor'},
+ 'description': {'en': 'The value', 'es': 'El valor'},
+ },
+ },
+ },
+}
+# ~ FUNCTIONS = {}
+
+EXTENSION = {
+ 'version': VERSION,
+ 'name': NAME,
+ 'id': ID,
+ 'icon': (ICON, ICON_EXT),
+}
+
+
+# If used more libraries set python path in True and copy inside
+DIRS = {
+ 'meta': 'META-INF',
+ 'source': 'source',
+ 'description': 'description',
+ 'images': 'images',
+ 'registration': 'registration',
+ 'files': 'files',
+ 'pythonpath': False,
+}
+
+
+FILES = {
+ 'oxt': f'{NAME}_v{VERSION}.oxt',
+ 'py': f'{NAME}.py',
+ 'ext_desc': 'desc_{}.txt',
+ 'manifest': 'manifest.xml',
+ 'description': 'description.xml',
+ 'idl': f'X{NAME}.idl',
+ 'addons': 'Addons.xcu',
+ 'urd': f'X{NAME}.urd',
+ 'rdb': f'X{NAME}.rdb',
+ 'update': f'{NAME.lower()}.update.xml',
+ 'addin': 'CalcAddIn.xcu',
+}
+
+
+# ~ URLs for update for example
+# ~ URL_XML_UPDATE = 'https://gitlab.com/USER/PROYECT/raw/BRANCH/FOLDERs/FILE_NAME'
+URL_XML_UPDATE = ''
+URL_OXT = ''
+
+
+# ~ If used user profile for develop
+# ~ PATH_DEV = '-env:UserInstallation=file:///home/mau/.temp/develop'
+# ~ unopkg not support (or I not know how) other user profile
+PATH_DEV = ''
+PATHS = {
+ 'idlc': '/usr/lib/libreoffice/sdk/bin/idlc',
+ 'include': '/usr/share/idl/libreoffice',
+ 'regmerge': '/usr/lib/libreoffice/program/regmerge',
+ 'soffice': ('soffice', '--calc'),
+ 'install': ('unopkg', 'add', '-v', '-f', '-s'),
+}
+
+
+SERVICES = {
+ 'job': "('com.sun.star.task.Job',)",
+ 'addin': "('com.sun.star.sheet.AddIn',)",
+}
+
+
+FORMAT = '%(asctime)s - %(levelname)s - %(message)s'
+DATE = '%d/%m/%Y %H:%M:%S'
+LEVEL_ERROR = logging.getLevelName(logging.ERROR)
+LEVEL_INFO = logging.getLevelName(logging.INFO)
+logging.addLevelName(logging.ERROR, f'\033[1;41m{LEVEL_ERROR}\033[1;0m')
+logging.addLevelName(logging.INFO, f'\x1b[32m{LEVEL_INFO}\033[1;0m')
+logging.basicConfig(level=logging.DEBUG, format=FORMAT, datefmt=DATE)
+log = logging.getLogger(NAME)
+
+
+def _methods():
+ template = """ def {0}(self, {1}):
+ print({1})
+ return 'ok'\n"""
+ functions = ''
+ for k, v in FUNCTIONS.items():
+ args = ','.join(v['parameters'].keys())
+ functions += template.format(k, args)
+ return functions
+
+
+SRV = SERVICES['job']
+XSRV = 'XJobExecutor'
+SRV_IMPORT = f'from com.sun.star.task import {XSRV}'
+METHODS = """ def trigger(self, args='pyUNO'):
+ print('Hello World', args)
+ return\n"""
+
+if TYPE_EXTENSION > 1:
+ MENUS = ()
+ XSRV = f'X{NAME}'
+ SRV_IMPORT = f'from {ID} import {XSRV}'
+if TYPE_EXTENSION == 2:
+ SRV = f"('{ID}',)"
+ METHODS = """ def test(self, args='pyUNO'):
+ print('Hello World', args)
+ return\n"""
+elif TYPE_EXTENSION == 3:
+ SRV = SERVICES['addin']
+ METHODS = _methods()
+
+
+FILE_PY = f"""import uno
+import unohelper
+{SRV_IMPORT}
+
+
+ID_EXTENSION = '{ID}'
+SERVICE = {SRV}
+
+
+class {NAME}(unohelper.Base, {XSRV}):
+
+ def __init__(self, ctx):
+ self.ctx = ctx
+
+{METHODS}
+
+g_ImplementationHelper = unohelper.ImplementationHelper()
+g_ImplementationHelper.addImplementation({NAME}, ID_EXTENSION, SERVICE)
+"""
+
+
+tmp = ' {}'
+node = [tmp.format(k, v['display_name']) for k, v in INFO.items()]
+NODE_DISPLAY_NAME = '\n'.join(node)
+
+tmp = ' '
+node = [tmp.format(k) for k, v in INFO.items()]
+NODE_EXTENSION_DESCRIPTION = '\n'.join(node)
+
+NODE_ICON = ''
+if ICON:
+ NODE_ICON = f' '
+
+NODE_PUBLISHER = ''
+if PUBLISHER:
+ tmp = ' {}'
+ node = [tmp.format(v['link'], k, v['text']) for k, v in PUBLISHER.items()]
+ NODE_PUBLISHER = '\n'.join(node)
+
+NODE_DEPENDENCIES_MINIMAL = ''
+if DEPENDENCIES_MINIMAL:
+ NODE_DEPENDENCIES_MINIMAL = f"""\n
+
+ """
+
+tmp = ' '
+node = [tmp.format(DIRS['registration'], k) for k in INFO.keys()]
+NODE_LICENSE = '\n'.join(node)
+
+NODE_UPDATE = ''
+if URL_XML_UPDATE:
+ NODE_UPDATE = f"""
+
+
+ """
+
+FILE_DESCRIPTION = f"""
+
+
+
+
+{NODE_DISPLAY_NAME}
+
+
+{NODE_EXTENSION_DESCRIPTION}
+
+
+{NODE_ICON}
+
+
+{NODE_PUBLISHER}
+
+
+
+{NODE_LICENSE}
+
+ {NODE_DEPENDENCIES_MINIMAL}{NODE_UPDATE}
+
+"""
+
+NODE_MENU = """
+
+{titles}
+
+
+ service:{id}?{argument}
+
+
+ _self
+
+
+ {context}
+
+
+ %origin%/{folder}/{icon}
+
+ """
+
+opt = 'fuse'
+if PARENT == 'OfficeMenuBar':
+ opt = 'replace'
+
+menus = []
+toolbar = []
+tmp = ' {}'
+for i, m in enumerate(MENUS):
+ titles = [tmp.format(k, v) for k, v in m['title'].items()]
+ values = {
+ 'id': ID,
+ 'index': i+101,
+ 'opt': opt,
+ 'titles': '\n'.join(titles),
+ 'argument': m['argument'],
+ 'context': m['context'],
+ 'folder': DIRS['images'],
+ 'icon': m['icon'],
+ }
+ menus.append(NODE_MENU.format(**values))
+ if m['toolbar']:
+ values['index'] = f't{i+1}'
+ toolbar.append(NODE_MENU.format(**values))
+
+NODE_TOOLBAR = ''
+if PARENT == 'AddonMenu':
+ NODE_MENUS = '\n'.join(menus)
+else:
+ tmp = ' {}'
+ titles = '\n'.join([tmp.format(k, v) for k, v in MENU_MAIN.items()])
+ SUBMENUS = '\n ' + '\n'.join(menus) + '\n '
+ NODE_MENUS = f"""
+
+{titles}
+
+
+ _self
+
+ {SUBMENUS}
+ """
+
+ if toolbar:
+ node_toolbars = '\n'.join(toolbar)
+ NODE_TOOLBAR = f"""
+
+{node_toolbars}
+
+ """
+
+FILE_ADDONS = f"""
+
+
+
+{NODE_MENUS}
+
+{NODE_TOOLBAR}
+
+
+"""
+
+
+NODE_ADDONS = '\n '
+if TYPE_EXTENSION > 1:
+ NODE_ADDONS = f'\n '
+if TYPE_EXTENSION == 3:
+ NODE_ADDONS += '\n '
+
+FILE_MANIFEST = f"""
+
+ {NODE_ADDONS}
+
+"""
+
+
+FILE_UPDATE = ''
+if URL_XML_UPDATE:
+ FILE_UPDATE = f"""
+
+
+
+
+
+
+
+
+
+
+
+"""
+
+
+def _functions():
+ a = '[in] any {}'
+ t = ' any {}({});'
+ f = ''
+ for k, v in FUNCTIONS.items():
+ args = ','.join([a.format(k) for k, v in v['parameters'].items()])
+ f += t.format(k, args)
+ return f
+
+
+FILE_IDL = ''
+if TYPE_EXTENSION > 1:
+ id_ext = ID.replace('.', '_')
+ interface = f'X{NAME}'
+ module = ''
+ for i, P in enumerate(ID.split('.')):
+ module += f'module {P} {{ '
+ close_module = '}; ' * (i + 1)
+ functions = ' void test([in] any argument);'
+ if TYPE_EXTENSION == 3:
+ functions = _functions()
+
+ FILE_IDL = f"""#ifndef __{id_ext}_idl__
+#define __{id_ext}_idl__
+
+#include
+
+{module}
+
+ interface {interface} : com::sun::star::uno::XInterface
+ {{
+{functions}
+ }};
+
+ service {P} {{
+ interface {interface};
+ }};
+
+{close_module}
+#endif
+"""
+
+
+def _parameters(args):
+ NODE = """
+
+{displayname}
+
+
+{description}
+
+ """
+ line = '{}{}'
+ node = ''
+ for k, v in args.items():
+ displayname = '\n'.join(
+ [line.format(' ' * 16, k, v) for k, v in v['displayname'].items()])
+ description = '\n'.join(
+ [line.format(' ' * 16, k, v) for k, v in v['description'].items()])
+ values = {
+ 'name': k,
+ 'displayname': displayname,
+ 'description': description,
+ }
+ node += NODE.format(**values)
+ return node
+
+
+NODE_FUNCTIONS = ''
+if TYPE_EXTENSION == 3:
+ tmp = '{}{}'
+ NODE_FUNCTION = """
+
+{displayname}
+
+
+{description}
+
+
+ Add-In
+
+
+ AutoAddIn.{name}
+
+
+{parameters}
+
+ """
+
+ for k, v in FUNCTIONS.items():
+ displayname = '\n'.join(
+ [tmp.format(' ' * 12, k, v) for k, v in v['displayname'].items()])
+ description = '\n'.join(
+ [tmp.format(' ' * 12, k, v) for k, v in v['description'].items()])
+ parameters = _parameters(v['parameters'])
+ values = {
+ 'name': k,
+ 'displayname': displayname,
+ 'description': description,
+ 'parameters': parameters,
+ }
+ NODE_FUNCTIONS += NODE_FUNCTION.format(**values)
+
+
+FILE_ADDIN = f"""
+
+
+
+
+{NODE_FUNCTIONS}
+
+
+
+"""
+
+
+DATA = {
+ 'py': FILE_PY,
+ 'manifest': FILE_MANIFEST,
+ 'description': FILE_DESCRIPTION,
+ 'addons': FILE_ADDONS,
+ 'update': FILE_UPDATE,
+ 'idl': FILE_IDL,
+ 'addin': FILE_ADDIN,
+}
diff --git a/source/images/icon_16.bmp b/source/images/icon_16.bmp
new file mode 100644
index 0000000..a954508
Binary files /dev/null and b/source/images/icon_16.bmp differ
diff --git a/source/images/logo.png b/source/images/logo.png
new file mode 100644
index 0000000..eccb275
Binary files /dev/null and b/source/images/logo.png differ
diff --git a/source/zaz.py b/source/zaz.py
new file mode 100644
index 0000000..917d7a0
--- /dev/null
+++ b/source/zaz.py
@@ -0,0 +1,269 @@
+# ~ This file is part of ZAZ.
+
+# ~ ZAZ 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.
+
+# ~ ZAZ 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 ZAZ. If not, see .
+
+import argparse
+import os
+import sys
+from shutil import copyfile
+from subprocess import call
+import zipfile
+
+from conf import (
+ DATA,
+ DIRS,
+ EXTENSION,
+ FILES,
+ INFO,
+ PATHS,
+ TYPE_EXTENSION,
+ log)
+
+
+def _exists(path):
+ return os.path.exists(path)
+
+
+def _join(*paths):
+ return os.path.join(*paths)
+
+
+def _mkdir(path):
+ return os.mkdir(path)
+
+
+def _save(path, data):
+ with open(path, 'w') as f:
+ f.write(data)
+ return
+
+
+def _compress_oxt():
+ log.info('Compress OXT extension...')
+
+ path = DIRS['files']
+ if not _exists(path):
+ _mkdir(path)
+
+ path_oxt = _join(path, FILES['oxt'])
+
+ z = zipfile.ZipFile(path_oxt, 'w', compression=zipfile.ZIP_DEFLATED)
+ root_len = len(os.path.abspath(DIRS['source']))
+ for root, dirs, files in os.walk(DIRS['source']):
+ relative = os.path.abspath(root)[root_len:]
+ for f in files:
+ fullpath = _join(root, f)
+ file_name = _join(relative, f)
+ if file_name == FILES['idl']:
+ continue
+ z.write(fullpath, file_name, zipfile.ZIP_DEFLATED)
+ z.close()
+
+ log.info('Extension OXT created sucesfully...')
+ return
+
+
+def _install_and_test():
+ path_oxt = (_join(DIRS['files'], FILES['oxt']),)
+ call(PATHS['install'] + path_oxt)
+ log.info('Install extension sucesfully...')
+ log.info('Start LibreOffice...')
+ call(PATHS['soffice'])
+ return
+
+
+def _validate_new():
+ path_source = DIRS['source']
+ if not _exists(path_source):
+ return True
+
+ msg = f'Path: {path_source}, exists, delete first'
+ log.error(msg)
+ return False
+
+
+def _create_new_directories():
+ path_source = DIRS['source']
+ _mkdir(path_source)
+ path = _join(path_source, DIRS['meta'])
+ _mkdir(path)
+ path = _join(path_source, DIRS['description'])
+ _mkdir(path)
+ path = _join(path_source, DIRS['images'])
+ _mkdir(path)
+ path = _join(path_source, DIRS['registration'])
+ _mkdir(path)
+
+ if DIRS['pythonpath']:
+ path = _join(path_source, DIRS['pythonpath'])
+ _mkdir(path)
+
+ path = DIRS['files']
+ if not _exists(path):
+ _mkdir(path)
+
+ msg = 'Created directories...'
+ log.info(msg)
+ return
+
+
+def _create_new_files():
+ path_source = DIRS['source']
+
+ for k, v in INFO.items():
+ file_name = f'license_{k}.txt'
+ path = _join(path_source, DIRS['registration'], file_name)
+ _save(path, v['license'])
+
+ if TYPE_EXTENSION > 1:
+ path = _join(path_source, FILES['idl'])
+ _save(path, DATA['idl'])
+
+ path = _join(path_source, FILES['py'])
+ _save(path, DATA['py'])
+
+ msg = 'Created files...'
+ log.info(msg)
+ return
+
+
+def _validate_update():
+ if TYPE_EXTENSION == 1:
+ return True
+
+ if not _exists(PATHS['idlc']):
+ msg = 'Binary: "idlc" not found'
+ log.error(msg)
+ return False
+
+ if not _exists(PATHS['include']):
+ msg = 'Directory: "include" not found'
+ log.error(msg)
+ return False
+
+ if not _exists(PATHS['regmerge']):
+ msg = 'Binary: "regmerge" not found'
+ log.error(msg)
+ return False
+
+ path = _join(DIRS['source'], FILES['idl'])
+ if not _exists(path):
+ msg = f'File: "{FILES["idl"]}" not found'
+ log.error(msg)
+ return False
+
+ return True
+
+
+def _compile_idl():
+ if TYPE_EXTENSION == 1:
+ return
+
+ log.info('Compilate IDL...')
+ path_rdb = _join(DIRS['source'], FILES['rdb'])
+ path_urd = _join(DIRS['source'], FILES['urd'])
+
+ path = _join(DIRS['source'], FILES['idl'])
+ call([PATHS['idlc'], '-I', PATHS['include'], path])
+ call([PATHS['regmerge'], path_rdb, '/UCR', path_urd])
+ os.remove(path_urd)
+
+ log.info('Compilate IDL sucesfully...')
+ return
+
+
+def _update_files():
+ path_source = DIRS['source']
+
+ for k, v in INFO.items():
+ file_name = FILES['ext_desc'].format(k)
+ path = _join(path_source, DIRS['description'], file_name)
+ _save(path, v['description'])
+
+ path_logo = EXTENSION['icon'][0]
+ if _exists(path_logo):
+ file_name = EXTENSION['icon'][1]
+ path = _join(path_source, DIRS['images'], file_name)
+ copyfile(path_logo, path)
+
+ files = os.listdir(DIRS['images'])
+ for f in files:
+ if f[-3:].lower() == 'bmp':
+ source = _join(DIRS['images'], f)
+ target = _join(path_source, DIRS['images'], f)
+ copyfile(source, target)
+
+ path = _join(path_source, DIRS['meta'], FILES['manifest'])
+ _save(path, DATA['manifest'])
+
+ path = _join(path_source, FILES['addons'])
+ _save(path, DATA['addons'])
+
+ path = _join(path_source, FILES['description'])
+ _save(path, DATA['description'])
+
+ if TYPE_EXTENSION == 3:
+ path = _join(path_source, FILES['addin'])
+ _save(path, DATA['addin'])
+
+ _compile_idl()
+ return
+
+
+def _new():
+ if not _validate_new():
+ return
+
+ _create_new_directories()
+ _create_new_files()
+ _update_files()
+
+ msg = f"New extension: {EXTENSION['name']} make sucesfully...\n"
+ msg += '\tNow, you can install and test: zaz.py -i'
+ log.info(msg)
+ return
+
+
+def main(args):
+ if args.new:
+ _new()
+ return
+
+ if not _validate_update():
+ return
+
+ _update_files()
+ _compress_oxt()
+
+ if args.install:
+ _install_and_test()
+
+ log.info('Extension make sucesfully...')
+ return
+
+
+def _process_command_line_arguments():
+ parser = argparse.ArgumentParser(
+ description='Make LibreOffice extensions')
+ parser.add_argument('-i', '--install', dest='install', action='store_true',
+ default=False, required=False)
+ parser.add_argument('-n', '--new', dest='new', action='store_true',
+ default=False, required=False)
+ return parser.parse_args()
+
+
+if __name__ == '__main__':
+ args = _process_command_line_arguments()
+ main(args)
+