changeset 4613:e7f1cf9eeb96

Static file serving built-in (see details below). Moved wiki/htdocs to MoinMoin/web/static/htdocs. MoinMoin.web.static has a static file serving wrapper that uses the files from htdocs subdirectory by default (docs=True). You can also give another path or switch off creation of that static wrapper. See the docstring of the static package for details. distutils had a major problem after I wanted it to just include everything below MoinMoin/web/static/htdocs - if you try to just use a glob ('htdocs/*'), it breaks distutils at 'setup.py install' time, because that glob matches directories and distutils only expects files. Therefore I added make_filelist to setup.py which creates just a list of all files below some specified directory.
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Sun, 01 Mar 2009 03:02:57 +0100
parents a6461afbc0ce
children 159902268129
files MANIFEST.in MoinMoin/_tests/test_sourcecode.py MoinMoin/script/server/standalone.py MoinMoin/web/frontend.py MoinMoin/web/serving.py MoinMoin/web/static/__init__.py setup.py wiki/server/moin.wsgi wiki/server/wikiserverconfig.py wikiserverconfig.py
diffstat 10 files changed, 158 insertions(+), 48 deletions(-) [+]
line wrap: on
line diff
--- a/MANIFEST.in	Sat Feb 28 22:35:16 2009 +0100
+++ b/MANIFEST.in	Sun Mar 01 03:02:57 2009 +0100
@@ -13,6 +13,9 @@
 # include stuff for translators
 recursive-include   MoinMoin/i18n *
 
+# include static htdocs
+recursive-include   MoinMoin/web/static/htdocs *
+
 # include non-py stuff from werkzeug
 recursive-include   MoinMoin/support/werkzeug/debug *
 
--- a/MoinMoin/_tests/test_sourcecode.py	Sat Feb 28 22:35:16 2009 +0100
+++ b/MoinMoin/_tests/test_sourcecode.py	Sun Mar 01 03:02:57 2009 +0100
@@ -21,9 +21,8 @@
     '/contrib/TWikiDrawPlugin', # 3rd party java stuff
     '/contrib/flup-server', # 3rd party WSGI adapters
     '/MoinMoin/support', # 3rd party libs or non-broken stdlib stuff
-    '/wiki/htdocs/applets/FCKeditor', # 3rd party GUI editor
+    '/MoinMoin/web/static/htdocs', # this is our dist static stuff
     '/tests/wiki', # this is our test wiki
-    '/wiki/htdocs', # this is our dist static stuff
     '/wiki/data/pages', # wiki pages, there may be .py attachments
 ]
 
--- a/MoinMoin/script/server/standalone.py	Sat Feb 28 22:35:16 2009 +0100
+++ b/MoinMoin/script/server/standalone.py	Sun Mar 01 03:02:57 2009 +0100
@@ -19,7 +19,7 @@
         MoinScript.__init__(self, argv, def_values)
         self.parser.add_option(
             "--docs", dest="docs",
-            help="Set the documents directory. Default: wiki/htdocs or /usr/share/moin/htdocs"
+            help="Set the documents directory. Default: use builtin MoinMoin/web/static/htdocs"
         )
         self.parser.add_option(
             "--user", dest="user",
@@ -107,12 +107,6 @@
             if self.options.debug:
                 Config.debug = True
 
-            if not hasattr(Config, 'docs'):
-                docs = os.path.join('wiki', 'htdocs')
-                if not os.path.exists(docs):
-                    docs = "/usr/share/moin/htdocs"
-                Config.docs = docs
-
             if self.options.start:
                 daemon = Daemon('moin', pidfile, run_server, Config)
                 daemon.do_start()
@@ -122,9 +116,13 @@
                            group=Config.group)
 
 class DefaultConfig:
-    docs = os.path.join('wiki', 'htdocs')
-    if not os.path.exists(docs):
-        docs = "/usr/share/moin/htdocs"
+    # where the static data is served from - you can either use:
+    # docs = True  # serve the builtin static data from MoinMoin/web/static/htdocs/
+    # docs = '/where/ever/you/like/to/keep/htdocs'  # serve it from the given path
+    # docs = False  # do not serve static files at all (will not work except
+    #               # you serve them in some other working way)
+    docs = True
+
     user = None
     group = None
     port = 8080
--- a/MoinMoin/web/frontend.py	Sat Feb 28 22:35:16 2009 +0100
+++ b/MoinMoin/web/frontend.py	Sun Mar 01 03:02:57 2009 +0100
@@ -26,8 +26,8 @@
                                 "configuration files. Default: current directory"))
         parser.add_option("--htdocs", dest="htdocs",
                           help=("Path to the directory containing Moin's "
-                                "static files. Default: /usr/share/moin/htdocs"))
-        parser.set_default('htdocs', '/usr/share/moin/htdocs')
+                                "static files. Default: use builtin MoinMoin/web/static/htdocs"))
+        parser.set_default('htdocs', True)
 
     def run(self, args=None):
         options, args = self.parser.parse_args(args)
--- a/MoinMoin/web/serving.py	Sat Feb 28 22:35:16 2009 +0100
+++ b/MoinMoin/web/serving.py	Sun Mar 01 03:02:57 2009 +0100
@@ -18,7 +18,7 @@
 import werkzeug._internal
 werkzeug._internal._logger = log.getLogger('werkzeug')
 
-from werkzeug import SharedDataMiddleware, run_simple
+from werkzeug import run_simple
 from werkzeug.serving import BaseRequestHandler
 
 class RequestHandler(BaseRequestHandler):
@@ -72,10 +72,8 @@
     Make an instance of the MoinMoin WSGI application. This involves
     wrapping it in middlewares as needed (static files, debugging, etc.).
 
-    @param shared: directory where static files are located (then we create the
-                   usual mapping dict we need automatically), or a ready-to-use
-                   mapping dict for SharedDataMiddleware. If None or empty, do
-                   not use the SharedDateMiddleware.
+    @param shared: see MoinMoin.web.static.make_static_serving_app.
+                   If falsy, do not use static serving app.
     @param trusted_proxies: list of trusted proxies. If None or empty, do not
                             use the ProxyTrust middleware.
     @rtype: callable
@@ -87,14 +85,8 @@
         application = ProxyTrust(application, trusted_proxies)
 
     if shared:
-        if not isinstance(shared, dict):
-            if os.path.isdir(shared):
-                shared = {config.url_prefix_static: shared,
-                          '/favicon.ico': os.path.join(shared, 'favicon.ico'),
-                          '/robots.txt': os.path.join(shared, 'robots.txt')}
-            else:
-                raise ValueError("Invalid path given for shared parameter")
-        application = SharedDataMiddleware(application, shared)
+        from MoinMoin.web.static import make_static_serving_app
+        application = make_static_serving_app(application, shared)
 
     return application
 
@@ -136,7 +128,7 @@
         raise RuntimeError("can't change uid/gid to %s/%s" % (uid, gid))
     logging.info("Running as uid/gid %d/%d" % (uid, gid))
 
-def run_server(host='localhost', port=8080, docs='/usr/share/moin/htdocs',
+def run_server(host='localhost', port=8080, docs=True,
                threaded=True, use_debugger=False, user=None, group=None):
     """ Run a standalone server on specified host/port. """
     application = make_application(shared=docs)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/web/static/__init__.py	Sun Mar 01 03:02:57 2009 +0100
@@ -0,0 +1,80 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - static files and serving them
+
+    MoinMoin uses some static files, like css, js, images, applets etc. and
+    they need to get served somehow.
+
+    How does moin use the static files?
+    -----------------------------------
+    Well, in fact, the moin wiki engine code does not access those files at all,
+    it just emits URLs to those files, so the browser of the wiki user will load
+    these files by requesting them from these URLs.
+
+    To generate correct URLs to these files, moin uses 2 configuration settings:
+    url_prefix_static - this the URL moin uses to generate URLs for static files,
+                        default: '/moin_staticXYZ' for moin version X.Y.Z
+    url_prefix_local - same thing, but some stuff is required to be on same server
+                       or the browser will reject it (e.g. FCKeditor javascript).
+                       So, if you point url_prefix_static to another server, you
+                       will have to give url_prefix_local with a URL on the same
+                       server.
+
+    Where are the static files located on your disk?
+    ------------------------------------------------
+    You can:
+    * Just serve our builtin static stuff from STATIC_FILES_PATH (in the moin code
+      at MoinMoin/web/static/htdocs) - in that case you should not modify the
+      files or your modifications could be overwritten when you upgrade moin.
+    * Copy that stuff to somewhere else and modify it THERE and use it from
+      THERE.
+
+    How to serve those static files?
+    --------------------------------
+    * Let moin serve them at <script_root>/moin_staticXYZ (this is the easiest
+      way, you can optimize it later) and use that by setting:
+      * for wikis running at root URL (/):
+        url_prefix_static = '/moin_staticXYZ' # this is the default!
+      * for wikis running at a non-root URL (like e.g. /mymoin):
+        from MoinMoin import config
+        url_prefix_static = '/mymoin' + config.url_prefix_static
+    * Later, you can serve them with your web server (e.g. apache) - you need to
+      configure apache to serve the url_prefix_static URL with the files from the
+      static files path.
+
+    @copyright: 2009 MoinMoin:ThomasWaldmann
+    @license: GNU GPL, see COPYING for details.
+"""
+
+from os.path import join, abspath, dirname, isdir
+
+from MoinMoin import config
+
+from werkzeug import SharedDataMiddleware
+
+STATIC_FILES_PATH = join(abspath(dirname(__file__)), 'htdocs')
+
+
+def make_static_serving_app(application, shared):
+    """
+    wrap application in a static file serving app
+
+    @param application: WSGI wiki application that should be wrapped
+    @param shared:  directory where static files are located (then we create the
+                    usual mapping dict we need automatically), or a ready-to-use
+                    mapping dict for SharedDataMiddleware.
+                    If True, use builtin static files from STATIC_FILES_PATH.
+    @returns: wrapped WSGI application
+    """
+    if not isinstance(shared, dict):
+        if shared is True:
+            shared = STATIC_FILES_PATH
+        if isdir(shared):
+            shared = {config.url_prefix_static: shared,
+                      # XXX only works / makes sense for root-mounted wikis:
+                      '/favicon.ico': join(shared, 'favicon.ico'),
+                      '/robots.txt': join(shared, 'robots.txt')}
+        else:
+            raise ValueError("Invalid path given for shared parameter")
+    return SharedDataMiddleware(application, shared)
+
--- a/setup.py	Sat Feb 28 22:35:16 2009 +0100
+++ b/setup.py	Sun Mar 01 03:02:57 2009 +0100
@@ -88,6 +88,26 @@
     destination = os.path.join(prefix, dirname[strip:])
     found.append((destination, files))
 
+def make_filelist(dir, strip_prefix=''):
+    """ package_data is pretty stupid: if the globs that can be given there
+        match a directory, then setup.py install will fall over that later,
+        because it expects only files.
+        Use make_filelist(dir, strip) to create a list of all FILES below dir,
+        stripping off the strip_prefix at the left side.
+    """
+    found = []
+    def _visit((found, strip), dirname, names):
+        files = []
+        for name in names:
+            path = os.path.join(dirname, name)
+            if os.path.isfile(path):
+                if path.startswith(strip):
+                    path = path[len(strip):]
+                files.append(path)
+        found.extend(files)
+
+    os.path.walk(dir, _visit, (found, strip_prefix))
+    return found
 
 #############################################################################
 ### Build script files
@@ -302,6 +322,7 @@
         'MoinMoin.userprefs',
         'MoinMoin.util',
         'MoinMoin.web',
+        'MoinMoin.web.static',
         'MoinMoin.widget',
         'MoinMoin.wikixml',
         'MoinMoin.xmlrpc',
@@ -310,12 +331,17 @@
         #'MoinMoin._tests',
     ],
 
-    'package_dir': {'MoinMoin.i18n': 'MoinMoin/i18n', },
+    'package_dir': {'MoinMoin.i18n': 'MoinMoin/i18n',
+                    'MoinMoin.web.static': 'MoinMoin/web/static',
+                   },
     'package_data': {'MoinMoin.i18n': ['README', 'Makefile', 'MoinMoin.pot', 'POTFILES.in',
                                        '*.po',
                                        'tools/*',
                                        'jabberbot/*',
-                                      ], },
+                                      ],
+                     'MoinMoin.web.static': make_filelist('MoinMoin/web/static/htdocs',
+                                                          strip_prefix='MoinMoin/web/static/'),
+                    },
 
     # Override certain command classes with our own ones
     'cmdclass': {
@@ -337,13 +363,14 @@
     setup_args['platforms'] = "any"
 
 
-try:
-    setup(**setup_args)
-except distutils.errors.DistutilsPlatformError, ex:
-    print
-    print str(ex)
+if __name__ == '__main__':
+    try:
+        setup(**setup_args)
+    except distutils.errors.DistutilsPlatformError, ex:
+        print
+        print str(ex)
 
-    print """
+        print """
 POSSIBLE CAUSE
 
 "distutils" often needs developer support installed to work
--- a/wiki/server/moin.wsgi	Sat Feb 28 22:35:16 2009 +0100
+++ b/wiki/server/moin.wsgi	Sun Mar 01 03:02:57 2009 +0100
@@ -4,15 +4,11 @@
 
     To use this, add those statements to your Apache's VirtualHost definition:
     
-    # this is for icons, css, js (and must match url_prefix from wiki config):
-    Alias       /moin_static190/ /usr/share/moin/htdocs/
-
-    # this is the URL http://servername/moin/ you will use later to invoke moin:
-    WSGIScriptAlias /moin/ /some/path/moin.wsgi
+    # you will invoke your moin wiki at the root url, like http://servername/FrontPage:
+    WSGIScriptAlias / /some/path/moin.wsgi
 
     # create some wsgi daemons - use someuser.somegroup same as your data_dir:
-    WSGIDaemonProcess daemonname user=someuser group=somegroup processes=5 threads=10 maximum-requests=1000
-    # umask=0007 does not work for mod_wsgi 1.0rc1, but will work later
+    WSGIDaemonProcess daemonname user=someuser group=somegroup processes=5 threads=10 maximum-requests=1000 umask=0007
 
     # use the daemons we defined above to process requests!
     WSGIProcessGroup daemonname
@@ -43,4 +39,11 @@
 #from MoinMoin import log
 #log.load_config('/path/to/logging_configuration_file')
 
-from MoinMoin.wsgiapp import application
+from MoinMoin.web.serving import make_application
+
+# Creating the WSGI application
+# use shared=True to have moin serve the builtin static docs
+# use shared=False to not have moin serve static docs
+# use shared='/my/path/to/htdocs' to serve static docs from that path
+application = make_application(shared=True)
+
--- a/wiki/server/wikiserverconfig.py	Sat Feb 28 22:35:16 2009 +0100
+++ b/wiki/server/wikiserverconfig.py	Sun Mar 01 03:02:57 2009 +0100
@@ -17,8 +17,12 @@
     # use '' for all interface or "1.2.3.4" for some specific IP
     #interface = 'localhost'
 
-    # where the static data is served from:
-    #docs = "/usr/share/moin/htdocs"
+    # where the static data is served from - you can either use:
+    # docs = True  # serve the builtin static data from MoinMoin/web/static/htdocs
+    # docs = '/where/ever/you/like/to/keep/htdocs'  # serve it from the given path
+    # docs = False  # do not serve static files at all (will not work except
+    #               # you serve them in some other working way)
+    docs = True
 
     # tuning options:
     #serverClass = 'ThreadPoolServer'
--- a/wikiserverconfig.py	Sat Feb 28 22:35:16 2009 +0100
+++ b/wikiserverconfig.py	Sun Mar 01 03:02:57 2009 +0100
@@ -17,8 +17,12 @@
     # use '' for all interface or "1.2.3.4" for some specific IP
     #interface = 'localhost'
 
-    # where the static data is served from:
-    #docs = "/usr/share/moin/htdocs"
+    # where the static data is served from - you can either use:
+    # docs = True  # serve the builtin static data from MoinMoin/web/static/htdocs
+    # docs = '/where/ever/you/like/to/keep/htdocs'  # serve it from the given path
+    # docs = False  # do not serve static files at all (will not work except
+    #               # you serve them in some other working way)
+    docs = True
 
     # tuning options:
     #serverClass = 'ThreadPoolServer'