From 850253ca41212d96ab53b49b135857c16e8605b8 Mon Sep 17 00:00:00 2001 From: Doug Blank Date: Mon, 3 Aug 2009 00:24:34 +0000 Subject: [PATCH] Removing experimental server code svn: r12863 --- src/cli/argparser.py | 11 +- src/cli/client.py | 151 --------------- src/cli/server.py | 440 ------------------------------------------- src/const.py.in | 2 - src/gramps.py | 4 - 5 files changed, 1 insertion(+), 607 deletions(-) delete mode 100644 src/cli/client.py delete mode 100644 src/cli/server.py diff --git a/src/cli/argparser.py b/src/cli/argparser.py index 086dda46a..24f1f42b3 100644 --- a/src/cli/argparser.py +++ b/src/cli/argparser.py @@ -66,7 +66,6 @@ Application options -l List Family Trees -L List Family Trees in Detail -u, --force-unlock Force unlock of family tree - -s, --server Start server in background """) #------------------------------------------------------------------------- @@ -123,7 +122,6 @@ class ArgParser(object): self.list_more = False self.help = False self.force_unlock = False - self.server = None self.errors = [] self.parse_args() @@ -215,8 +213,6 @@ class ArgParser(object): self.help = True elif option in ('-u', '--force-unlock'): self.force_unlock = True - elif option in ('-s', '--server'): - self.server = value #clean options list cleandbg.reverse() @@ -224,8 +220,7 @@ class ArgParser(object): del options[ind] if len(options) > 0 and self.open is None and self.imports == [] \ - and not (self.list or self.list_more or self.help) \ - and self.server is None: + and not (self.list or self.list_more or self.help): self.errors += [(_('Error parsing the arguments'), _("Error parsing the arguments: %s \n" "To use in the command-line mode," \ @@ -238,10 +233,6 @@ class ArgParser(object): """ Determine whether we need a GUI session for the given tasks. """ - # If we have explicitly put gramps in server mode: - if self.server is not None: - return False # we do not want the gui - if self.errors: #errors in argument parsing ==> give cli error, no gui needed return False diff --git a/src/cli/client.py b/src/cli/client.py deleted file mode 100644 index 2c9d7a5ce..000000000 --- a/src/cli/client.py +++ /dev/null @@ -1,151 +0,0 @@ -# -# Gramps - a GTK+/GNOME based genealogy program -# -# Copyright (C) 2009 Doug Blank -# -# 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; either version 2 of the License, or -# (at your option) any later version. -# -# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# - -# $Id$ - -import pickle -import socket -import sys - -from gen.lib import * - -class RemoteObject: - """ - A wrapper to access underlying attributes by asking over a - socket. A server will pickle the result, and return. - """ - def __init__(self, host, port, prefix = "self."): - self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.socket.connect((host, port)) - self.socket.settimeout(5) # 5 second timeout - self.prefix = prefix - - def __repr__(self): - return self.remote("repr(self)") - - def person(self, handle): - data = self.remote("self.dbstate.db.get_raw_person_data(%s)" % repr(handle)) - return Person(data) - - def family(self, handle): - data = self.remote("self.dbstate.db.get_raw_family_data(%s)" % repr(handle)) - return Family(data) - - def object(self, handle): - data = self.remote("self.dbstate.db.get_raw_object_data(%s)" % repr(handle)) - return MediaObject(data) - - def place(self, handle): - data = self.remote("self.dbstate.db.get_raw_place_data(%s)" % repr(handle)) - return Place(data) - - def event(self, handle): - data = self.remote("self.dbstate.db.get_raw_event_data(%s)" % repr(handle)) - return Event(data) - - def source(self, handle): - data = self.remote("self.dbstate.db.get_raw_source_data(%s)" % repr(handle)) - return Source(data) - - def repository(self, handle): - data = self.remote("self.dbstate.db.get_raw_repository_data(%s)" % repr(handle)) - return Repository(data) - - def note(self, handle): - data = self.remote("self.dbstate.db.get_raw_note_data(%s)" % repr(handle)) - return Note(data) - - def remote(self, command): - """ - Use this interface to directly talk to server. - """ - retval = None - self.socket.send(command) - data = self.socket.recv(1024) - if data != "": - while True: - try: - retval = pickle.loads(data) - break - except: - data += self.socket.recv(1024) - if isinstance(retval, Exception): - raise retval - return retval - - def _eval(self, item, *args, **kwargs): - """ - The interface for calling prefix.item.item...(args, kwargs) - """ - commandArgs = "" - for a in args: - if commandArgs != "": - commandArgs += ", " - commandArgs += repr(a) - for a in kwargs.keys(): - if commandArgs != "": - commandArgs += ", " - commandArgs += a + "=" + repr(kwargs[a]) - self.socket.send(self.prefix + item + "(" + commandArgs + ")") - retval = None - data = self.socket.recv(1024) - if data != "": - while True: - try: - retval = pickle.loads(data) - break - except: - data += self.socket.recv(1024) - return retval - - def representation(self, item): - return self.remote("repr(%s)" % (self.prefix + item)) - - def __getattr__(self, item): - return TempRemoteObject(self, item) - - def dir(self, item = ''): - return self.remote("dir(%s)" % ((self.prefix + item)[:-1])) - -class TempRemoteObject: - """ - Temporary field/method access object. - """ - def __init__(self, parent, item): - self.parent = parent - self.item = item - def __call__(self, *args, **kwargs): - return self.parent._eval(self.item, *args, **kwargs) - def _eval(self, prefix, *args, **kwargs): - return self.parent._eval(self.item + "." + prefix, *args, **kwargs) - def __repr__(self): - return self.parent.representation(self.item) - def representation(self, item): - return self.parent.representation(self.item + "." + item) - def __getattr__(self, item): - return TempRemoteObject(self, item) - def dir(self, item = ''): - return self.parent.dir(self.item + "." + item) - -if __name__ == "__main__": - host = sys.argv[1] - port = int(sys.argv[2]) - self = RemoteObject(host, port) - print "GRAMPS Remote interface; use 'self' to access GRAMPS" diff --git a/src/cli/server.py b/src/cli/server.py deleted file mode 100644 index 636ed58c2..000000000 --- a/src/cli/server.py +++ /dev/null @@ -1,440 +0,0 @@ -# -# Gramps - a GTK+/GNOME based genealogy program -# -# Copyright (C) 2009 Doug Blank -# -# 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; either version 2 of the License, or -# (at your option) any later version. -# -# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# - -# $Id$ - -""" -Provides the start_server function, which the main program calls for server -execution of GRAMPS. - -Provides also two small base classes: CLIDbLoader, CLIManager -""" - -#------------------------------------------------------------------------- -# -# Python modules -# -#------------------------------------------------------------------------- -import socket -import threading -import pickle -from gettext import gettext as _ -import os -import sys -import signal -import logging -import traceback - -LOG = logging.getLogger(".grampscli") -#------------------------------------------------------------------------- -# -# GRAMPS modules -# -#------------------------------------------------------------------------- -from BasicUtils import name_displayer -import Config -import const -import Errors -import DbState -from gen.db import (GrampsDBDir, FileVersionDeclineToUpgrade) -import gen.db.exceptions -from gen.plug import PluginManager -from Utils import get_researcher -import RecentFiles -import Simple - -#------------------------------------------------------------------------- -# -# CLI DbLoader class -# -#------------------------------------------------------------------------- -class CLIDbLoader(object): - """ - Base class for Db loading action inside a dbstate. Only the minimum is - present needed for CLI handling - """ - def __init__(self, dbstate): - self.dbstate = dbstate - - def _warn(self, title, warnmessage): - """ - Issue a warning message. Inherit for GUI action - """ - print _('WARNING: %s') % warnmessage - - def _errordialog(self, title, errormessage): - """ - Show the error. A title for the error and an errormessage - Inherit for GUI action - """ - print _('ERROR: %s') % errormessage - sys.exit(1) - - def _dberrordialog(self, msg): - """ - Show a database error. - @param: msg : an error message - @type: string - @note: Inherit for GUI action - """ - self._errordialog( '', _("Low level database corruption detected") - + '\n' + - _("GRAMPS has detected a problem in the underlying " - "Berkeley database. This can be repaired by from " - "the Family Tree Manager. Select the database and " - 'click on the Repair button') + '\n\n' + str(msg)) - - def _begin_progress(self): - """ - Convenience method to allow to show a progress bar if wanted on load - actions. Inherit if needed - """ - pass - - def _pulse_progress(self, value): - """ - Convenience method to allow to show a progress bar if wantedon load - actions. Inherit if needed - """ - pass - - def read_file(self, filename): - """ - This method takes care of changing database, and loading the data. - In 3.0 we only allow reading of real databases of filetype - 'x-directory/normal' - - This method should only return on success. - Returning on failure makes no sense, because we cannot recover, - since database has already beeen changed. - Therefore, any errors should raise exceptions. - - On success, return with the disabled signals. The post-load routine - should enable signals, as well as finish up with other UI goodies. - """ - - if os.path.exists(filename): - if not os.access(filename, os.W_OK): - mode = "r" - self._warn(_('Read only database'), - _('You do not have write access ' - 'to the selected file.')) - else: - mode = "w" - else: - mode = 'w' - - dbclass = GrampsDBDir - - self.dbstate.change_database(dbclass()) - self.dbstate.db.disable_signals() - - self._begin_progress() - - try: - self.dbstate.db.load(filename, self._pulse_progress, mode) - self.dbstate.db.set_save_path(filename) - except FileVersionDeclineToUpgrade: - self.dbstate.no_database() - except gen.db.exceptions.FileVersionError, msg: - self.dbstate.no_database() - self._errordialog( _("Cannot open database"), str(msg)) - except OSError, msg: - self.dbstate.no_database() - self._errordialog( - _("Could not open file: %s") % filename, str(msg)) - except Errors.DbError, msg: - self.dbstate.no_database() - self._dberrordialog(msg) - except Exception: - self.dbstate.no_database() - LOG.error("Failed to open database.", exc_info=True) - return True - -#------------------------------------------------------------------------- -# -# CLIManager class -# -#------------------------------------------------------------------------- - -class CLIManager(object): - """ - Sessionmanager for GRAMPS. This is in effect a reduced viewmanager - instance (see gui/viewmanager), suitable for CLI actions. - Aim is to manage a dbstate on which to work (load, unload), and interact - with the plugin session - """ - def __init__(self, dbstate, setloader): - self.dbstate = dbstate - if setloader: - self.db_loader = CLIDbLoader(self.dbstate) - else: - self.db_loader = None - self.file_loaded = False - self._pmgr = PluginManager.get_instance() - - def open_activate(self, path): - """ - Open and make a family tree active - """ - self._read_recent_file(path) - - def _errordialog(self, title, errormessage): - """ - Show the error. A title for the error and an errormessage - """ - print _('ERROR: %s') % errormessage - sys.exit(1) - - def _read_recent_file(self, filename): - """ - Called when a file needs to be loaded - """ - # A recent database should already have a directory If not, do nothing, - # just return. This can be handled better if family tree delete/rename - # also updated the recent file menu info in DisplayState.py - if not os.path.isdir(filename): - self._errordialog( - _("Could not load a recent Family Tree."), - _("Family Tree does not exist, as it has been deleted.")) - return - - if self.db_loader.read_file(filename): - # Attempt to figure out the database title - path = os.path.join(filename, "name.txt") - try: - ifile = open(path) - title = ifile.readline().strip() - ifile.close() - except: - title = filename - - self._post_load_newdb(filename, 'x-directory/normal', title) - - def _post_load_newdb(self, filename, filetype, title=None): - """ - The method called after load of a new database. - Here only CLI stuff is done, inherit this method to add extra stuff - """ - self._post_load_newdb_nongui(filename, title) - - def _post_load_newdb_nongui(self, filename, title=None): - """ - Called after a new database is loaded. - """ - if not filename: - return - - if filename[-1] == os.path.sep: - filename = filename[:-1] - name = os.path.basename(filename) - if title: - name = title - - # This method is for UI stuff when the database has changed. - # Window title, recent files, etc related to new file. - - self.dbstate.db.set_save_path(filename) - - # apply preferred researcher if loaded file has none - res = self.dbstate.db.get_researcher() - owner = get_researcher() - if res.get_name() == "" and owner.get_name() != "": - self.dbstate.db.set_researcher(owner) - - name_displayer.set_name_format(self.dbstate.db.name_formats) - fmt_default = Config.get(Config.NAME_FORMAT) - if fmt_default < 0: - name_displayer.set_default_format(fmt_default) - - self.dbstate.db.enable_signals() - self.dbstate.signal_change() - - Config.set(Config.RECENT_FILE, filename) - - try: - self.dbstate.change_active_person( - self.dbstate.db.find_initial_person()) - except: - pass - - RecentFiles.recent_files(filename, name) - self.file_loaded = True - - def do_load_plugins(self): - """ - Loads the plugins at initialization time. The plugin status window is - opened on an error if the user has requested. - """ - # load plugins - - error = self._pmgr.load_plugins(const.PLUGINS_DIR) - error |= self._pmgr.load_plugins(const.USER_PLUGINS) - - return error - -def start_server(errors, argparser): - """ - Starts a cli session of GRAMPS. - errors : errors already encountered - argparser : ArgParser instance - """ - if errors: - #already errors encountered. Show first one on terminal and exit - print _('Error encountered: %s') % errors[0][0] - print _(' Details: %s') % errors[0][1] - sys.exit(1) - - if argparser.errors: - print _('Error encountered in argument parsing: %s') \ - % argparser.errors[0][0] - print _(' Details: %s') % argparser.errors[0][1] - sys.exit(1) - - #we need to keep track of the db state - dbstate = DbState.DbState() - #we need a manager for the CLI session - climanager = CLIManager(dbstate, True) - #load the plugins - climanager.do_load_plugins() - # handle the arguments - from arghandler import ArgHandler - handler = ArgHandler(dbstate, argparser, climanager) - # create a manager to manage the database - handler.handle_args_cli(cleanup=False) # cleanup later - simple_access = Simple.SimpleAccess(dbstate.db) - # server request handler: - port = int(argparser.server) - server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_socket.bind(("", port)) - server_socket.listen(5) - # Set the signal handler - signal.signal(signal.SIGINT, - lambda signum, frame: ctrlc_handler(signum, frame, handler)) - print "GRAMPS server listening on port %d." % port - print "Use CONTROL+C to exit..." - print "-" * 50 - remote_interface = RemoteInterfaceHandler(dbstate, climanager, handler, - simple_access) - while True: # keep handling requests - client_socket, client_address = server_socket.accept() - BackgroundThread(client_socket, client_address, remote_interface).run() - -def ctrlc_handler(signum, frame, handler): - """ - Control+c program to handle clean up of databases, unlocking tables, etc. - Exits the server. - """ - handler.cleanup() - sys.exit(0) - -class RemoteInterfaceHandler: - """ - Class that handles requests that come in on a socket connection via - the GRAMPS remote interface. - """ - def __init__(self, dbstate, climanager, arghandler, simple_access): - """ - Constructor for RI. Pass in objects necessary for interacting with - data and reports. - """ - self.dbstate = dbstate - self.climanager = climanager - self.arghandler = arghandler - self.sdb = simple_access - self.env = {} - self.env["self"] = self - - def reset(self): - self.env = {} - self.env["self"] = self - - def eval(self, command): - """ - Evaluate the remote command and return results. - """ - retval = None - try: - retval = eval(command, self.env) - except: - exec command in self.env - retval = "ok" - return retval - -class BackgroundThread(threading.Thread): - """ - A thread class for running things in the background. - """ - def __init__(self, socket, address, remote_api, pause = 0.01): - """ - Constructor, setting initial variables - """ - self.client_socket = socket - self.client_address = address - self.remote_api = remote_api - self._stopevent = threading.Event() - self._sleepperiod = pause - threading.Thread.__init__(self, name="GRAMPS Server Thread") - - def run(self): - """ - overload of threading.thread.run() - main control loop - """ - print "Connection opened from %s:%s" % (self.client_address[0], - self.client_address[1]) - while not self._stopevent.isSet(): - self.process() - print "Connection closed from %s:%s" % (self.client_address[0], - self.client_address[1]) - self.client_socket.close() - - def join(self,timeout=None): - """ - Stop the thread - """ - self._stopevent.set() - threading.Thread.join(self, timeout) - self.client_socket.close() - - def process(self): - """ - Process a remote request. - """ - try: - data = self.client_socket.recv(1024) - except: - data = None - if data: - print " Request:", data - try: - result = self.remote_api.eval(data) - presult = pickle.dumps(result) - except Exception as exception: - result = exception - presult = pickle.dumps(result) - - try: - self.client_socket.send(presult) - except: - print "Error in sending data. Continuing anyway." - else: - self._stopevent.set() - diff --git a/src/const.py.in b/src/const.py.in index df9ff7e06..638d6e0bf 100644 --- a/src/const.py.in +++ b/src/const.py.in @@ -220,7 +220,6 @@ POPT_TABLE = [ ("", 'l', None, None, 0, 'List Family Trees', ""), ("", 'L', None, None, 0, 'List Family Tree Details', ""), ("force-unlock", 'u', None, None, 0, 'Force unlock of family tree', ""), - ("server", 's', str, None, 0, 'Start GRAMPS server', "SERVER"), ] LONGOPTS = [ @@ -251,7 +250,6 @@ LONGOPTS = [ "oaf-private", "open=", "options=", - "server=", "screen=", "sm-client-id=", "sm-config-prefix=", diff --git a/src/gramps.py b/src/gramps.py index 0597bfed6..0fa5880d5 100644 --- a/src/gramps.py +++ b/src/gramps.py @@ -168,10 +168,6 @@ def run(): #A GUI is needed, set it up from gui.grampsgui import startgtkloop startgtkloop(error, argpars) - elif argpars.server is not None: - # Server, no CLI - from cli.server import start_server - start_server(error, argpars) else: #CLI use of GRAMPS argpars.print_help()