From 840f426dc64e9fb9bf97b70a2a93743acd0b8f4d Mon Sep 17 00:00:00 2001
From: Wannes Rombouts <wapiflapi@yahoo.fr>
Date: Thu, 6 Jun 2013 15:21:39 +0200
Subject: [PATCH] First draft, config files are updated, basic plugin handling
 is in place, but we still need to define the hooks.

---
 plugins/__init__.py | 38 +++++++++++++++++++++++++
 src/extensions.py   | 68 +++++++++++++++++++++++++++++++++++++++++++++
 src/mra.yaml.sample | 10 +++++++
 src/mralogs.py      | 10 ++++++-
 src/server.py       |  8 +++++-
 5 files changed, 132 insertions(+), 2 deletions(-)
 create mode 100644 plugins/__init__.py
 create mode 100644 src/extensions.py

diff --git a/plugins/__init__.py b/plugins/__init__.py
new file mode 100644
index 0000000..347ed97
--- /dev/null
+++ b/plugins/__init__.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python2.7
+# -*- coding: utf-8 -*-
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+#                                                                       #
+#   MapServer REST API is a python wrapper around MapServer which       #
+#   allows to manipulate a mapfile in a RESTFul way. It has been        #
+#   developped to match as close as possible the way the GeoServer      #
+#   REST API acts.                                                      #
+#                                                                       #
+#   Copyright (C) 2011-2013 Neogeo Technologies.                        #
+#                                                                       #
+#   This file is part of MapServer Rest API.                            #
+#                                                                       #
+#   MapServer Rest API 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.                 #
+#                                                                       #
+#   MapServer Rest API 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.                        #
+#                                                                       #
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+# This package is used for easy management of plugins. Just drop them in
+# this folder and they will automatically be loaded if this folder is
+# present in the mra.yaml configuration under plugins/loadpaths
+
+import os, os.path
+
+__all__ = []
+for module in os.listdir(os.path.dirname(__file__)):
+    name, ext = os.path.splitext(module)
+    if name != "__init__" and ext in ["", ".py"]:
+        __all__.append(name)
+
diff --git a/src/extensions.py b/src/extensions.py
new file mode 100644
index 0000000..562f251
--- /dev/null
+++ b/src/extensions.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python2.7
+# -*- coding: utf-8 -*-
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+#                                                                       #
+#   MapServer REST API is a python wrapper around MapServer which       #
+#   allows to manipulate a mapfile in a RESTFul way. It has been        #
+#   developped to match as close as possible the way the GeoServer      #
+#   REST API acts.                                                      #
+#                                                                       #
+#   Copyright (C) 2011-2013 Neogeo Technologies.                        #
+#                                                                       #
+#   This file is part of MapServer Rest API.                            #
+#                                                                       #
+#   MapServer Rest API 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.                 #
+#                                                                       #
+#   MapServer Rest API 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.                        #
+#                                                                       #
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+import sys
+import os.path
+import logging
+
+class ExtensionManager(object):
+
+    def __init__(self, ):
+        self.extentions = {}
+
+    def load_plugins(self, pkg_name):
+        sys.path.append(__file__)
+        __import__(pkg_name, globals(), locals(), ["*"])
+        sys.path.remove(__file__)
+
+    def load_plugins_dir(self, dir_path):
+        path, pkg = os.path.split(os.path.abspath(dir_path))
+        pkg, _ = os.path.splitext(pkg)
+        print "Loading %s from %s" % (pkg, path)
+
+        sys.path.append(path)
+        try:
+            self.load_plugins(pkg)
+        except ImportError:
+            logging.error("Could not load plugin package '%s' from %s" % (pkg, path))
+        else:
+            logging.info("Loaded plugin package '%s' from %s" % (pkg, path))
+        sys.path.remove(path)
+
+    def extend(self, name, *args, **kwargs):
+        for f in self.extentions.get(name, []):
+            f(*args, **kwargs)
+
+    def register(self, name, f=None):
+        if f == None:
+            def decorator(f):
+                self.register(name, f)
+                return f
+            return decorator
+
+        self.extentions.setdefault(name, []).append(f)
+
+plugins = ExtensionManager()
diff --git a/src/mra.yaml.sample b/src/mra.yaml.sample
index cd7c43e..c984464 100644
--- a/src/mra.yaml.sample
+++ b/src/mra.yaml.sample
@@ -27,3 +27,13 @@ testing:
     active: False
     # Which map file to use to create new test files.
     model: model
+
+plugins:
+    # The paths in this lists will be loaded as plugins.
+    # A plugin can be a python package, if that is the case it
+    # should define the __all__ attribute to indicate which modules
+    # should be handled as plugins. (An example can be found in /plugins)
+
+    loadpaths: [
+#       "/path/to/your/plugins"
+    ]
diff --git a/src/mralogs.py b/src/mralogs.py
index 0614301..98580c9 100644
--- a/src/mralogs.py
+++ b/src/mralogs.py
@@ -24,6 +24,7 @@
 #                                                                       #
 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
 
+import sys
 import string
 import inspect
 import logging
@@ -31,7 +32,14 @@ import functools
 
 def setup(log_level, log_file=None, format="%(asctime)s %(levelname)7s: %(message)s"):
     log_level = getattr(logging, log_level.upper())
-    logging.basicConfig(filename=log_file, format=format, level=log_level)
+
+    if log_file:
+        logging.basicConfig(filename=log_file, format=format, level=log_level)
+
+    sh = logging.StreamHandler(sys.stderr)
+    sh.setLevel(log_level)
+    sh.setFormatter(logging.Formatter(format))
+    logging.getLogger().addHandler(sh)
 
 class Reccord(logging.Handler):
     """A logging.Handler class which stores the records.
diff --git a/src/server.py b/src/server.py
index 3338899..cd472c5 100755
--- a/src/server.py
+++ b/src/server.py
@@ -24,6 +24,8 @@
 #                                                                       #
 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
 
+import os.path
+
 import web
 import json
 import urlparse
@@ -41,7 +43,8 @@ from tools import get_mapfile, get_mapfile_workspace, get_config, href
 
 from pyxml import Entries
 
-import os.path
+
+from extensions import plugins
 
 mralogs.setup(get_config("logging")["level"], get_config("logging")["file"],
               get_config("logging")["format"])
@@ -991,6 +994,9 @@ web.config.debug = get_config("debug").get("web_debug", False)
 webapp.exceptionManager.raise_all = get_config("debug").get("raise_all", False)
 HTTPCompatible.return_logs = get_config("logging").get("web_logs", False)
 
+for pdir in get_config("plugins").get("loadpaths", []):
+    plugins.load_plugins_dir(pdir)
+
 app = web.application(urls, globals())
 
 if __name__ == "__main__":
-- 
GitLab