Added a new option for the UNO communication port. Updated the use of print for Python 3 compatibility (for LibreOffice). Replaced sys.stderr.write() with Python 3 print(). Changed the help text from OpenOffice to OpenOffice/LibreOffice. Added several TODO items.

This commit is contained in:
依瑪貓 2016-12-22 19:54:18 +08:00
parent cef4425d28
commit 1f90f2e407
2 changed files with 53 additions and 37 deletions

5
TODO
View File

@ -1,3 +1,6 @@
obasync TODO obasync TODO
* Adds a README. * File extension.
* Writes the README (reStructureText).
* Documentation.
* Python 3

85
bin/obasync Normal file → Executable file
View File

@ -3,6 +3,7 @@
# Office Basic macro source synchronizer. # Office Basic macro source synchronizer.
# by imacat <imacat@mail.imacat.idv.tw>, 2016-08-31 # by imacat <imacat@mail.imacat.idv.tw>, 2016-08-31
from __future__ import print_function
import argparse import argparse
import os import os
import sys import sys
@ -12,7 +13,6 @@ import time
def append_uno_path(): def append_uno_path():
""" Appends the path of the uno module to the import path. """ """ Appends the path of the uno module to the import path. """
is_found_uno = False
for p in sys.path: for p in sys.path:
if os.path.exists(os.path.join(p, "uno.py")): if os.path.exists(os.path.join(p, "uno.py")):
return return
@ -43,13 +43,14 @@ def main():
parse_args() parse_args()
# Connects to the OpenOffice # Connects to the OpenOffice
oo = OpenOffice() oo = OpenOffice(args.port)
# Synchronize the Basic macros. # Synchronize the Basic macros.
sync_macros(oo) sync_macros(oo)
print >> sys.stderr, "Done. %02d:%02d elapsed." % \ print("Done. %02d:%02d elapsed." %
(int((time.time() - t_start) / 60), (time.time() - t_start) % 60) (int((time.time() - t_start) / 60),
(time.time() - t_start) % 60), file=sys.stderr)
def parse_args(): def parse_args():
@ -58,7 +59,7 @@ def parse_args():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description=("Synchronize the local Basic scripts" description=("Synchronize the local Basic scripts"
" with OpenOffice Basic.")) " with OpenOffice/LibreOffice Basic."))
parser.add_argument( parser.add_argument(
"projdir", metavar="dir", nargs="?", default=os.getcwd(), "projdir", metavar="dir", nargs="?", default=os.getcwd(),
help=("The project source directory" help=("The project source directory"
@ -70,6 +71,10 @@ def parse_args():
parser.add_argument( parser.add_argument(
"--get", action="store_true", "--get", action="store_true",
help="Downloads the macros instead of upload.") help="Downloads the macros instead of upload.")
parser.add_argument(
"-p", "--port", metavar="N", type=int, default=2002,
help=("The TCP port to communicate with "
"OpenOffice/LibreOffice with (default: %(default)s)"))
parser.add_argument( parser.add_argument(
"-r", "--run", metavar="Module.Macro", "-r", "--run", metavar="Module.Macro",
help="The macro to run after the upload, if any.") help="The macro to run after the upload, if any.")
@ -96,8 +101,8 @@ def sync_macros(oo):
if args.get: if args.get:
modules = read_basic_modules(libraries, args.library) modules = read_basic_modules(libraries, args.library)
if len(modules) == 0: if len(modules) == 0:
print >> sys.stderr, \ print("ERROR: Library %s does not exist" % args.library,
"ERROR: Library " + args.library + " does not exist" file=sys.stderr)
return return
update_source_dir(args.projdir, modules) update_source_dir(args.projdir, modules)
@ -105,8 +110,9 @@ def sync_macros(oo):
else: else:
modules = read_in_source_dir(args.projdir) modules = read_in_source_dir(args.projdir)
if len(modules) == 0: if len(modules) == 0:
print >> sys.stderr, \ print("ERROR: Found no source macros in %s" %
"ERROR: Found no source macros in " + args.projdir args.projdir,
file=sys.stderr)
return return
update_basic_modules(libraries, args.library, modules, oo) update_basic_modules(libraries, args.library, modules, oo)
if args.run is not None: if args.run is not None:
@ -115,9 +121,9 @@ def sync_macros(oo):
"theMasterScriptProviderFactory") "theMasterScriptProviderFactory")
provider = factory.createScriptProvider("") provider = factory.createScriptProvider("")
script = provider.getScript( script = provider.getScript(
"vnd.sun.star.script:" "vnd.sun.star.script:%s.%s"
+ args.library + "." + args.run "?language=Basic&location=application" %
+ "?language=Basic&location=application") (args.library, args.run))
script.invoke((), (), ()) script.invoke((), (), ())
return return
@ -151,25 +157,27 @@ def update_source_dir(projdir, modules):
f = open(path, "w") f = open(path, "w")
f.write(modules[modname]) f.write(modules[modname])
f.close() f.close()
print >> sys.stderr, modname + ".vb added." print("%s.vb added." % modname, file=sys.stderr)
is_in_sync = False is_in_sync = False
else: else:
path = os.path.join(projdir, curmods[modname]) path = os.path.join(projdir, curmods[modname])
f = open(path, "r+") f = open(path, "r+")
if modules[modname] != f.read().replace("\r\n", "\n"): if modules[modname] != f.read().replace("\r\n", "\n"):
f.seek(0) f.seek(0)
f.truncate(0)
f.write(modules[modname]) f.write(modules[modname])
print >> sys.stderr, curmods[modname] + " updated." print("%s updated." % curmods[modname],
file=sys.stderr)
is_in_sync = False is_in_sync = False
f.close() f.close()
for modname in sorted(curmods.keys()): for modname in sorted(curmods.keys()):
if modname not in modules: if modname not in modules:
path = os.path.join(projdir, curmods[modname]) path = os.path.join(projdir, curmods[modname])
os.remove(path) os.remove(path)
print >> sys.stderr, curmods[modname] + " removed." print("%s removed." % curmods[modname], file=sys.stderr)
is_in_sync = False is_in_sync = False
if is_in_sync: if is_in_sync:
print >> sys.stderr, "Everything is in sync." print("Everything is in sync.", file=sys.stderr)
return return
@ -189,12 +197,12 @@ def update_basic_modules(libraries, libname, modules, oo):
""" Updates the OpenOffice Basic macros storage. """ """ Updates the OpenOffice Basic macros storage. """
if not libraries.hasByName(libname): if not libraries.hasByName(libname):
libraries.createLibrary(libname) libraries.createLibrary(libname)
print >> sys.stderr, "Script library " + libname + " created." print("Script library %s created." % libname, file=sys.stderr)
create_dialog_library(oo, libname) create_dialog_library(oo, libname)
library = libraries.getByName(libname) library = libraries.getByName(libname)
for modname in sorted(modules.keys()): for modname in sorted(modules.keys()):
library.insertByName(modname, modules[modname]) library.insertByName(modname, modules[modname])
print >> sys.stderr, "Module " + modname + " added." print("Module %s added." % modname, file=sys.stderr)
else: else:
libraries.loadLibrary(libname) libraries.loadLibrary(libname)
library = libraries.getByName(libname) library = libraries.getByName(libname)
@ -202,18 +210,18 @@ def update_basic_modules(libraries, libname, modules, oo):
for modname in sorted(modules.keys()): for modname in sorted(modules.keys()):
if modname not in curmods: if modname not in curmods:
library.insertByName(modname, modules[modname]) library.insertByName(modname, modules[modname])
print >> sys.stderr, "Module " + modname + " added." print("Module %s added." % modname, file=sys.stderr)
elif modules[modname] != library.getByName(modname): elif modules[modname] != library.getByName(modname):
library.replaceByName(modname, modules[modname]) library.replaceByName(modname, modules[modname])
print >> sys.stderr, "Module " + modname + " updated." print("Module %s updated." % modname, file=sys.stderr)
for modname in curmods: for modname in curmods:
if modname not in modules: if modname not in modules:
library.removeByName(modname) library.removeByName(modname)
print >> sys.stderr, "Module " + modname + " removed." print("Module %s removed." % modname, file=sys.stderr)
if libraries.isModified(): if libraries.isModified():
libraries.storeLibraries() libraries.storeLibraries()
else: else:
print >> sys.stderr, "Everything is in sync." print("Everything is in sync.", file=sys.stderr)
return return
@ -222,15 +230,16 @@ def create_dialog_library(oo, libname):
libraries = oo.service_manager.createInstance( libraries = oo.service_manager.createInstance(
"com.sun.star.script.ApplicationDialogLibraryContainer") "com.sun.star.script.ApplicationDialogLibraryContainer")
libraries.createLibrary(libname) libraries.createLibrary(libname)
print >> sys.stderr, "Dialog library " + libname + " created." print("Dialog library %s created." % libname, file=sys.stderr)
libraries.storeLibraries() libraries.storeLibraries()
class OpenOffice: class OpenOffice:
""" The OpenOffice connection. """ """ The OpenOffice connection. """
def __init__(self): def __init__(self, port=2002):
"""Initializes the object.""" """Initializes the object."""
self.port = port
self.bootstrap_context = None self.bootstrap_context = None
self.service_manager = None self.service_manager = None
self.desktop = None self.desktop = None
@ -246,8 +255,8 @@ class OpenOffice:
url_resolver = local_service_manager.createInstanceWithContext( url_resolver = local_service_manager.createInstanceWithContext(
"com.sun.star.bridge.UnoUrlResolver", local_context) "com.sun.star.bridge.UnoUrlResolver", local_context)
# Obtains the context # Obtains the context
url = ("uno:socket,host=localhost,port=2002;" url = ("uno:socket,host=localhost,port=%d;"
"urp;StarOffice.ComponentContext") "urp;StarOffice.ComponentContext") % self.port
while True: while True:
try: try:
self.bootstrap_context = url_resolver.resolve(url) self.bootstrap_context = url_resolver.resolve(url)
@ -266,31 +275,35 @@ class OpenOffice:
# For MS-Windows, which does not have fork() # For MS-Windows, which does not have fork()
if os.name == "nt": if os.name == "nt":
from subprocess import Popen from subprocess import Popen
ooexec = os.path.join(os.path.dirname(uno.__file__), "soffice.exe") ooexec = os.path.join(
os.path.dirname(uno.__file__), "soffice.exe")
DETACHED_PROCESS = 0x00000008 DETACHED_PROCESS = 0x00000008
Popen([ooexec, "-accept=socket,host=localhost,port=2002;urp;"], Popen([ooexec,
"-accept=socket,host=localhost,port=%d;urp;" %
self.port],
close_fds=True, creationflags=DETACHED_PROCESS) close_fds=True, creationflags=DETACHED_PROCESS)
time.sleep(2) time.sleep(2)
return return
# For POSIX systems, including Linux # For POSIX systems, including Linux and MacOSX
try: try:
pid = os.fork() pid = os.fork()
except OSError: except OSError:
sys.stderr.write("failed to fork().\n") print("Failed to fork().", file=sys.stderr)
sys.exit(1) sys.exit(1)
if pid != 0: if pid != 0:
time.sleep(2) time.sleep(2)
return return
os.setsid() os.setsid()
ooexec = os.path.join(os.path.dirname(uno.__file__), "soffice") ooexec = os.path.join(
os.path.dirname(uno.__file__), "soffice")
try: try:
os.execl( os.execl(ooexec, ooexec,
ooexec, ooexec, "-accept=socket,host=localhost,port=%d;urp;" %
"-accept=socket,host=localhost,port=2002;urp;") self.port)
except OSError: except OSError:
sys.stderr.write( print("%s: Failed to run the OpenOffice server." % ooexec,
ooexec + ": Failed to run the OpenOffice server.\n") file=sys.stderr)
sys.exit(1) sys.exit(1)
if __name__ == "__main__": if __name__ == "__main__":