Browse Source

Hyde now has a auto regenerating, barebones http server

main
Lakshmi Vyasarajan 14 years ago
parent
commit
63ef5efa0b
9 changed files with 191 additions and 12 deletions
  1. +34
    -7
      hyde/engine.py
  2. +18
    -1
      hyde/fs.py
  3. +2
    -1
      hyde/generator.py
  4. +4
    -2
      hyde/layouts/test/site.yaml
  5. +1
    -0
      hyde/model.py
  6. +123
    -0
      hyde/server.py
  7. +1
    -1
      hyde/site.py
  8. +7
    -0
      hyde/tests/test_fs.py
  9. +1
    -0
      hyde/tests/test_model.py

+ 34
- 7
hyde/engine.py View File

@@ -49,7 +49,7 @@ class Engine(Application):
The create command. Creates a new site from the template at the given The create command. Creates a new site from the template at the given
sitepath. sitepath.
""" """
sitepath = Folder(args.sitepath)
sitepath = Folder(Folder(args.sitepath).fully_expanded_path)
if sitepath.exists and not args.overwrite: if sitepath.exists and not args.overwrite:
raise HydeException( raise HydeException(
"The given site path[%s] is not empty" % sitepath) "The given site path[%s] is not empty" % sitepath)
@@ -75,14 +75,41 @@ class Engine(Application):
The generate command. Generates the site at the given The generate command. Generates the site at the given
deployment directory. deployment directory.
""" """
sitepath = Folder(args.sitepath)
site = self.make_site(args.sitepath, args.config)
from hyde.generator import Generator
gen = Generator(site)
gen.generate_all()

@subcommand('serve', help='Serve the website')
@store('-a', '--address', default='localhost', dest='address',
help='The address where the website must be served from.')
@store('-p', '--port', type=int, default=8080, dest='port',
help='The port where the website must be served from.')
@store('-c', '--config-path', default='site.yaml', dest='config',
help='The configuration used to generate the site')
@store('-d', '--deploy-path', default='deploy',
help='Where should the site be generated?')
def serve(self, args):
"""
The serve command. Serves the site at the given
deployment directory, address and port. Regenerates
the entire site or specific files based on ths request.
"""
sitepath = Folder(Folder(args.sitepath).fully_expanded_path)
config_file = sitepath.child(args.config) config_file = sitepath.child(args.config)
site = self.make_site(args.sitepath, args.config)
from hyde.server import HydeWebServer
server = HydeWebServer(site, args.address, args.port)
server.serve_forever()

def make_site(self, sitepath, config):
"""
Creates a site object from the given sitepath and the config file.
"""
sitepath = Folder(Folder(sitepath).fully_expanded_path)
config_file = sitepath.child(config)
logger.info("Reading site configuration from [%s]", config_file) logger.info("Reading site configuration from [%s]", config_file)
conf = {} conf = {}
with open(config_file) as stream: with open(config_file) as stream:
conf = yaml.load(stream) conf = yaml.load(stream)
site = Site(sitepath, Config(sitepath, conf))

from hyde.generator import Generator
gen = Generator(site)
gen.generate_all()
return Site(sitepath, Config(sitepath, conf))

+ 18
- 1
hyde/fs.py View File

@@ -27,9 +27,11 @@ class FS(object):
""" """
The base file system object The base file system object
""" """

def __init__(self, path): def __init__(self, path):
super(FS, self).__init__() super(FS, self).__init__()
self.path = os.path.expanduser(str(path).strip().rstrip(os.sep))
self.path = os.path.expandvars(os.path.expanduser(
str(path).strip().rstrip(os.sep)))


def __str__(self): def __str__(self):
return self.path return self.path
@@ -43,6 +45,18 @@ class FS(object):
def __ne__(self, other): def __ne__(self, other):
return str(self) != str(other) return str(self) != str(other)


@property
def fully_expanded_path(self):
"""
Returns the absolutely absolute path. Calls os.(
normpath, normcase, expandvars and expanduser).
"""
return os.path.abspath(
os.path.normpath(
os.path.normcase(
os.path.expandvars(
os.path.expanduser(self.path)))))

@property @property
def exists(self): def exists(self):
""" """
@@ -142,6 +156,7 @@ class File(FS):
""" """
The File object. The File object.
""" """

def __init__(self, path): def __init__(self, path):
super(File, self).__init__(path) super(File, self).__init__(path)


@@ -436,6 +451,7 @@ class Folder(FS):
""" """
Represents a directory. Represents a directory.
""" """

def __init__(self, path): def __init__(self, path):
super(Folder, self).__init__(path) super(Folder, self).__init__(path)


@@ -510,6 +526,7 @@ class Folder(FS):
""" """
source = self source = self
with source.walker as walker: with source.walker as walker:

@walker.folder_visitor @walker.folder_visitor
def visit_folder(folder): def visit_folder(folder):
""" """


+ 2
- 1
hyde/generator.py View File

@@ -81,7 +81,8 @@ class Generator(object):
if not self.template: if not self.template:
logger.info("Generating site at [%s]" % self.site.sitepath) logger.info("Generating site at [%s]" % self.site.sitepath)
self.template = Template.find_template(self.site) self.template = Template.find_template(self.site)
logger.info("Using [%s] as the template", self.template)
logger.info("Using [%s] as the template",
self.template.__class__.__name__)


logger.info("Configuring the template environment") logger.info("Configuring the template environment")
self.template.configure(self.site.config) self.template.configure(self.site.config)


+ 4
- 2
hyde/layouts/test/site.yaml View File

@@ -2,6 +2,8 @@ mode: development
media_root:: media # Relative path from site root (the directory where this file exists) media_root:: media # Relative path from site root (the directory where this file exists)
media_url: /media media_url: /media
template: hyde.ext.jinja2 template: hyde.ext.jinja2
widgets:
plugins: plugins:
aggregators:
- hyde.ext.plugins.meta.MetaPlugin
- hyde.ext.plugins.auto_extend.AutoExtendPlugin
- hyde.ext.plugins.less.LessCSSPlugin
- hyde.ext.plugins.blockdown.BlockdownPlugin

+ 1
- 0
hyde/model.py View File

@@ -51,6 +51,7 @@ class Config(Expando):
layout_root='layout', layout_root='layout',
media_url='/media', media_url='/media',
site_url='/', site_url='/',
not_found='404.html',
plugins = [] plugins = []
) )
conf = dict(**default_config) conf = dict(**default_config)


+ 123
- 0
hyde/server.py View File

@@ -0,0 +1,123 @@
"""
Contains classes and utilities for serving a site
generated from hyde.
"""
import os
import urlparse
import urllib
from SimpleHTTPServer import SimpleHTTPRequestHandler
from BaseHTTPServer import HTTPServer
from hyde.fs import File, Folder
from hyde.site import Site
from hyde.generator import Generator

import logging

logger = logging.getLogger('hyde.server')

import sys
logger.addHandler(logging.StreamHandler(sys.stdout))

class HydeRequestHandler(SimpleHTTPRequestHandler):
"""
Serves files by regenerating the resource (or)
everything when a request is issued.
"""

def do_GET(self):
"""
Idenitfy the requested path. If the query string
contains `refresh`, regenerat the entire site.
Otherwise, regenerate only the requested resource
and serve.
"""
logger.info("Processing request:[%s]" % self.path)
result = urlparse.urlparse(self.path)
query = urlparse.parse_qs(result.query)
if 'refresh' in query:
self.server.regenerate()
del query['refresh']
parts = tuple(result)
parts[4] = urllib.urlencode(query)
new_url = urlparse.urlunparse(parts)
logger.info('Redirecting...[%s]' % new_url)
self.redirect(new_url)
else:
try:
SimpleHTTPRequestHandler.do_GET(self)
except Exception, exception:
logger.error(exception.message)
site = self.server.site
res = site.content.resource_from_relative_path(
site.config.not_found)
self.redirect("/" + res.relative_deploy_path)

def translate_path(self, path):
"""
Finds the absolute path of the requested file by
referring to the `site` variable in the server.
"""
site = self.server.site
result = urlparse.urlparse(self.path)
logger.info("Trying to load file based on request:[%s]" % result.path)
path = result.path.lstrip('/')
res = site.content.resource_from_relative_path(path)
if not res:
logger.info("Cannot load file:[%s]" % path)
raise Exception("Cannot load file: [%s]" % path)
else:
self.server.generate_resource(res)
new_path = site.config.deploy_root_path.child(
res.relative_deploy_path)
return new_path

def redirect(self, path, temporary=True):
"""
Sends a redirect header with the new location.
"""
self.send_response(302 if temporary else 301)
self.send_header('Location', path)
self.end_headers()


class HydeWebServer(HTTPServer):
"""
The hyde web server that regenerates the resource, node or site when
a request is issued.
"""

def __init__(self, site, address, port):
self.site = site
self.site.load()
self.generator = Generator(self.site)

HTTPServer.__init__(self, (address, port),
HydeRequestHandler)

def __reinit__(self):
self.generator = Generator(self.site)
self.regenerate()

def regenerate(self):
"""
Regenerates the entire site.
"""
try:
logger.info('Regenerating the entire site')
self.generator.generate_all()
except Exception, exception:
logger.error('Error occured when regenerating the site [%s]'
% exception.message)
self.__reinit__()

def generate_resource(self, resource):
"""
Regenerates the entire site.
"""
try:
logger.info('Generating resource [%]' % resource)
self.generator.generate_resource(resource)
except Exception, exception:
logger.error('Error [%s] occured when generating the resource [%s]'
% (resource, repr(exception)))
self.__reinit__()

+ 1
- 1
hyde/site.py View File

@@ -311,7 +311,7 @@ class Site(object):


def __init__(self, sitepath=None, config=None): def __init__(self, sitepath=None, config=None):
super(Site, self).__init__() super(Site, self).__init__()
self.sitepath = Folder(str(sitepath))
self.sitepath = Folder(Folder(sitepath).fully_expanded_path)
self.config = config if config else Config(self.sitepath) self.config = config if config else Config(self.sitepath)
self.content = RootNode(self.config.content_root_path, self) self.content = RootNode(self.config.content_root_path, self)
self.plugins = [] self.plugins = []


+ 7
- 0
hyde/tests/test_fs.py View File

@@ -60,6 +60,13 @@ def test_path_expands_user():
f = File("~/abc/def") f = File("~/abc/def")
assert f.path == os.path.expanduser("~/abc/def") assert f.path == os.path.expanduser("~/abc/def")


def test_fully_expanded_path():
f = File(__file__).parent
n = f.child_folder('../' + f.name)
e = Folder(n.fully_expanded_path)
assert n != e
assert f == e

def test_parent(): def test_parent():
f = File(__file__) f = File(__file__)
p = f.parent p = f.parent


+ 1
- 0
hyde/tests/test_model.py View File

@@ -77,6 +77,7 @@ class TestConfig(object):
assert hasattr(c, 'plugins') assert hasattr(c, 'plugins')
assert len(c.plugins) == 0 assert len(c.plugins) == 0
assert c.deploy_root_path == TEST_SITE_ROOT.child_folder('deploy') assert c.deploy_root_path == TEST_SITE_ROOT.child_folder('deploy')
assert c.not_found == '404.html'


def test_conf1(self): def test_conf1(self):
c = Config(sitepath=TEST_SITE_ROOT, config_dict=yaml.load(self.conf1)) c = Config(sitepath=TEST_SITE_ROOT, config_dict=yaml.load(self.conf1))


Loading…
Cancel
Save