#!/usr/bin/env python # # KeepNote - note-taking and organization # Copyright (c) 2008-2009 Matt Rasmussen # Author: Matt Rasmussen # # This program 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; version 2 of the License. # # This program 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 this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. # # python imports import exceptions import sys import os from os.path import basename, dirname, realpath, join, isdir import time import optparse import thread import traceback #============================================================================= # KeepNote import """ Three ways to run KeepNote bin_path = os.path.dirname(sys.argv[0]) (1) directly from source dir pkgdir = bin_path + "../keepnote" basedir = pkgdir sys.path.append(pkgdir) src/bin/keepnote src/keepnote/__init__.py src/keepnote/images src/keepnote/rc (2) from installation location by setup.py pkgdir = keepnote.get_basedir() basedir = pkgdir prefix/bin/keepnote prefix/lib/python-XXX/site-packages/keepnote/__init__.py prefix/lib/python-XXX/site-packages/keepnote/images prefix/lib/python-XXX/site-packages/keepnote/rc (3) windows py2exe dir pkgdir = bin_path basedir = bin_path dir/keepnote.exe dir/library.zip dir/images dir/rc """ # try to infer keepnote lib path from program path pkgdir = dirname(dirname(realpath(sys.argv[0]))) if os.path.exists(os.path.join(pkgdir, "keepnote", "__init__.py")): sys.path.append(pkgdir) import keepnote # if this works we know we are running from src_path (1) basedir = keepnote.get_basedir() else: # try to import from python path import keepnote # sucessful import, therefore we are running with (2) or (3) # attempt to use basedir for (2) basedir = keepnote.get_basedir() if not isdir(join(basedir, "images")): # we must be running (3) basedir = dirname(realpath(sys.argv[0])) #============================================================================= # keepnote imports import keepnote from keepnote.commands import get_command_executor, CommandExecutor from keepnote.teefile import TeeFileStream import keepnote.compat.pref _ = keepnote.translate #============================================================================= # command-line options o = optparse.OptionParser(usage= "%prog [options] [NOTEBOOK]") o.set_defaults(default_notebook=True) o.add_option("-c", "--cmd", dest="cmd", action="store_true", help="treat remaining arguments as a command") o.add_option("-l", "--list-cmd", dest="list_cmd", action="store_true", help="list available commands") o.add_option("--no-gui", dest="no_gui", action="store_true", help="run in non-gui mode") o.add_option("", "--show-errors", dest="show_errors", action="store_true", help="show errors on console") o.add_option("--no-show-errors", dest="show_errors", action="store_false", help="do not show errors on console") o.add_option("--no-default", dest="default_notebook", action="store_false", help="do not open default notebook") o.add_option("", "--newproc", dest="newproc", action="store_true", help="start KeepNote in a new process") o.add_option("-p", "--port", dest="port", default=None, type="int", help="use a specified port for listening to commands") #============================================================================= def start_error_log(show_errors): """Starts KeepNote error log""" keepnote.init_error_log() # Test ability to write to file[-like] objects used to display errors. # - if stderr is unavailable, create error message, else add to stream # list. Do not exit. # Note: this code-section is necessary to allow Linux-users the option of # launching KeepNote from a *.desktop file without having it # run in a terminal (currently, KeepNote must be allowed to spawn # a terminal window when launching from a *.desktop file). In other # words, 'Terminal=false' can be safely added to the *.desktop file; # without this section, adding 'Terminal=false' to the *.desktop file # causes KeepNote launch failure. stream_list = [] stderr_test_str = "\n" stderr_except_msg = "" try: if show_errors: sys.stderr.write(stderr_test_str) except IOError: formatted_msg = traceback.format_exc().splitlines() stderr_except_msg = ''.join(['** stderr - unavailable for messages - ', formatted_msg[-1], "\n"]) else: stream_list.append(sys.stderr) # if errorlog is unavailable, exit with error, else add to stream list. try: errorlog = open(keepnote.get_user_error_log(), "a") except IOError: sys.exit(traceback.print_exc()) else: stream_list.append(errorlog) if show_errors: sys.stderr = TeeFileStream(stream_list, autoflush=True) else: sys.stderr = errorlog sys.stderr.write("==============================================\n" "%s %s: %s\n" % (keepnote.PROGRAM_NAME, keepnote.PROGRAM_VERSION_TEXT, time.asctime())) sys.stderr.write(stderr_except_msg) def parse_argv(argv): """Parse arguments""" # set default arguments options = o.get_default_values() if keepnote.get_platform() == "windows": options.show_errors = False else: options.show_errors = True # parse args and process (options, args) = o.parse_args(argv[1:], options) return options, args def setup_threading(): """Initialize threading environment""" import gtk.gdk import gobject if keepnote.get_platform() == "windows": # HACK: keep gui thread active def sleeper(): time.sleep(.001) return True # repeat timer gobject.timeout_add(400, sleeper) else: gtk.gdk.threads_init() def gui_exec(function, *args, **kw): """Execute a function in the GUI thread""" import gtk.gdk import gobject def idle_func(): gtk.gdk.threads_enter() try: function(*args, **kw) return False finally: gtk.gdk.threads_leave() gobject.idle_add(idle_func) def start_gui(argv, options, args, cmd_exec): import keepnote.gui # pygtk imports import pygtk pygtk.require('2.0') import gtk # setup threading environment setup_threading() # start error log start_error_log(options.show_errors) # read preferences app = keepnote.gui.KeepNote(basedir) app.init() cmd_exec.set_app(app) execute_command(app, argv) gtk.main() def start_non_gui(argv, options, args, cmd_exec): # start error log start_error_log(options.show_errors) # read preferences app = keepnote.KeepNote(basedir) app.init() cmd_exec.set_app(app) execute_command(app, argv) def execute_command(app, argv): """Execute commands given on command line""" options, args = parse_argv(argv) # parse builtin commands if options.list_cmd: list_commands(app) sys.exit() if options.cmd: # process application command (AppCommand) if len(args) == 0: raise Exception(_("Expected command")) command = app.get_command(args[0]) if command: command.func(app, args) else: raise Exception(_("Unknown command '%s'") % args[0]) # start first window if not options.no_gui: if len(app.get_windows()) == 0: app.new_window() else: # process a non-command if options.no_gui: sys.exit() if len(args) > 0: if keepnote.extension.is_extension_install_file(args[0]): # install extension if len(app.get_windows()) == 0: app.new_window() app.install_extension(args[0]) else: # open specified notebook win = app.new_window() win.open_notebook(args[0].rstrip("/")) else: # no arguments if options.default_notebook and app.pref.get("default_notebook", default="") != "": # open default notebook win = app.new_window() win.open_notebook(app.pref.get("default_notebook")) else: # open empty window app.new_window() def list_commands(app): """List available commands""" commands = app.get_commands() commands.sort(key=lambda x: x.name) print print "available commands:" for command in commands: print " " + command.name, if command.metavar: print " " + command.metavar, if command.help: print " -- " + command.help, print def main(argv): """Main execution""" options, args = parse_argv(argv) # check for old preference info keepnote.compat.pref.check_old_user_pref_dir() # init preference dir if not os.path.exists(keepnote.get_user_pref_dir()): keepnote.init_user_pref_dir() # get command executor if options.newproc: main_proc = True cmd_exec = CommandExecutor() else: try: main_proc, cmd_exec = get_command_executor( lambda app, argv: gui_exec( lambda: execute_command(app, argv)), port=options.port) except: # backup if error is encountered acquiring lock main_proc = True cmd_exec = CommandExecutor() if main_proc: # initiate main process if options.no_gui: start_non_gui(argv, options, args, cmd_exec) else: start_gui(argv, options, args, cmd_exec) else: # this is a command process, send command to main process cmd_exec.execute(argv) try: main(sys.argv) except exceptions.SystemExit, e: # sys.exit() was called pass except Exception, e: traceback.print_exc() # flush final errors sys.stderr.flush()