PageRenderTime 58ms CodeModel.GetById 13ms app.highlight 40ms RepoModel.GetById 1ms app.codeStats 0ms

/hyde/server.py

http://github.com/hyde/hyde
Python | 211 lines | 183 code | 9 blank | 19 comment | 9 complexity | 6d8e9de26fd88b8edb50f09d98522f7e MD5 | raw file
  1# -*- coding: utf-8 -*-
  2"""
  3Contains classes and utilities for serving a site
  4generated from hyde.
  5"""
  6import threading
  7import urllib
  8import traceback
  9from datetime import datetime
 10
 11
 12from hyde._compat import (HTTPServer, iteritems, parse, PY3,
 13                          SimpleHTTPRequestHandler, unquote)
 14from hyde.generator import Generator
 15
 16from fswrap import File, Folder
 17
 18from commando.util import getLoggerWithNullHandler
 19logger = getLoggerWithNullHandler('hyde.server')
 20
 21
 22class HydeRequestHandler(SimpleHTTPRequestHandler):
 23
 24    """
 25    Serves files by regenerating the resource (or)
 26    everything when a request is issued.
 27    """
 28
 29    def do_GET(self):
 30        """
 31        Identify the requested path. If the query string
 32        contains `refresh`, regenerat the entire site.
 33        Otherwise, regenerate only the requested resource
 34        and serve.
 35        """
 36        self.server.request_time = datetime.now()
 37        logger.debug("Processing request: [%s]" % self.path)
 38        result = parse.urlparse(self.path)
 39        query = parse.parse_qs(result.query)
 40        if 'refresh' in query or result.query == 'refresh':
 41            self.server.regenerate()
 42            if 'refresh' in query:
 43                del query['refresh']
 44            parts = list(tuple(result))
 45            parts[4] = urllib.urlencode(query)
 46            parts = tuple(parts)
 47            new_url = parse.urlunparse(parts)
 48            logger.info('Redirecting... [%s]' % new_url)
 49            self.redirect(new_url)
 50        else:
 51            SimpleHTTPRequestHandler.do_GET(self)
 52
 53    def translate_path(self, path):
 54        """
 55        Finds the absolute path of the requested file by
 56        referring to the `site` variable in the server.
 57        """
 58        site = self.server.site
 59        path = unquote(self.path)
 60        if not PY3:
 61            path = path.decode('utf-8')
 62        result = parse.urlparse(path)
 63        logger.debug(
 64            "Trying to load file based on request: [%s]" % result.path)
 65        path = result.path.lstrip('/')
 66        res = None
 67        if path.strip() == "" or File(path).kind.strip() == "":
 68            deployed = site.config.deploy_root_path.child(path)
 69            deployed = Folder.file_or_folder(deployed)
 70            if isinstance(deployed, Folder):
 71                node = site.content.node_from_relative_path(path)
 72                res = node.get_resource('index.html')
 73            elif hasattr(site.config, 'urlcleaner') and hasattr(
 74                    site.config.urlcleaner, 'strip_extensions'):
 75                for ext in site.config.urlcleaner.strip_extensions:
 76                    res = site.content.resource_from_relative_deploy_path(
 77                        path + '.' + ext)
 78                    if res:
 79                        break
 80                for ext in site.config.urlcleaner.strip_extensions:
 81                    new_path = site.config.deploy_root_path.child(
 82                        path + '.' + ext)
 83                    if File(new_path).exists:
 84                        return new_path
 85        else:
 86            res = site.content.resource_from_relative_deploy_path(path)
 87
 88        if not res:
 89            logger.error("Cannot load file: [%s]" % path)
 90            return site.config.deploy_root_path.child(path)
 91        else:
 92            self.server.generate_resource(res)
 93        new_path = site.config.deploy_root_path.child(
 94            res.relative_deploy_path)
 95        return new_path
 96
 97    def do_404(self):
 98        """
 99        Sends a 'not found' response.
100        """
101        site = self.server.site
102        if self.path != site.config.not_found:
103            self.redirect(site.config.not_found)
104        else:
105            res = site.content.resource_from_relative_deploy_path(
106                site.config.not_found)
107
108            message = "Requested resource not found"
109            if not res:
110                logger.error(
111                    "Cannot find the 404 template [%s]."
112                    % site.config.not_found)
113            else:
114                f404 = File(self.translate_path(site.config.not_found))
115                if f404.exists:
116                    message = f404.read_all()
117            self.send_response(200, message)
118
119    def redirect(self, path, temporary=True):
120        """
121        Sends a redirect header with the new location.
122        """
123        self.send_response(302 if temporary else 301)
124        self.send_header('Location', path)
125        self.end_headers()
126
127
128class HydeWebServer(HTTPServer):
129
130    """
131    The hyde web server that regenerates the resource, node or site when
132    a request is issued.
133    """
134
135    def __init__(self, site, address, port):
136        self.site = site
137        self.site.load()
138        self.generator = Generator(self.site)
139        self.request_time = datetime.strptime('1-1-1999', '%m-%d-%Y')
140        self.regeneration_time = datetime.strptime('1-1-1998', '%m-%d-%Y')
141        self.__is_shut_down = threading.Event()
142        self.__shutdown_request = False
143        self.map_extensions()
144        HTTPServer.__init__(self, (address, port),
145                            HydeRequestHandler)
146
147    def map_extensions(self):
148        """
149        Maps extensions specified in the configuration.
150        """
151        try:
152            extensions = self.site.config.server.extensions.to_dict()
153        except AttributeError:
154            extensions = {}
155
156        for extension, type in iteritems(extensions):
157            ext = "." + extension if not extension == 'default' else ''
158            HydeRequestHandler.extensions_map[ext] = type
159
160    def regenerate(self):
161        """
162        Regenerates the entire site.
163        """
164        try:
165            logger.info('Regenerating the entire site')
166            self.regeneration_time = datetime.now()
167            if self.site.config.needs_refresh():
168                self.site.config.reload()
169            self.site.load()
170            self.generator.generate_all(incremental=False)
171        except Exception as exception:
172            logger.error('Error occured when regenerating the site [%s]'
173                         % exception.message)
174            logger.debug(traceback.format_exc())
175
176    def generate_node(self, node):
177        """
178        Generates the given node.
179        """
180
181        deploy = self.site.config.deploy_root_path
182        if not deploy.exists:
183            return self.regenerate()
184
185        try:
186            logger.debug('Serving node [%s]' % node)
187            self.generator.generate_node(node, incremental=True)
188        except Exception as exception:
189            logger.error(
190                'Error [%s] occured when generating the node [%s]'
191                % (repr(exception), node))
192            logger.debug(traceback.format_exc())
193
194    def generate_resource(self, resource):
195        """
196        Regenerates the given resource.
197        """
198        deploy = self.site.config.deploy_root_path
199        if not deploy.exists:
200            return self.regenerate()
201        dest = deploy.child_folder(resource.node.relative_path)
202        if not dest.exists:
203            return self.generate_node(resource.node)
204        try:
205            logger.debug('Serving resource [%s]' % resource)
206            self.generator.generate_resource(resource, incremental=True)
207        except Exception as exception:
208            logger.error(
209                'Error [%s] occured when serving the resource [%s]'
210                % (repr(exception), resource))
211            logger.debug(traceback.format_exc())