PageRenderTime 44ms CodeModel.GetById 17ms app.highlight 22ms RepoModel.GetById 1ms app.codeStats 0ms

/hyde/engine.py

http://github.com/hyde/hyde
Python | 161 lines | 120 code | 12 blank | 29 comment | 13 complexity | ca2db73dd17347417d2d4f6a48657d4c MD5 | raw file
  1# -*- coding: utf-8 -*-
  2"""
  3Implements the hyde entry point commands
  4"""
  5from hyde.exceptions import HydeException
  6from hyde.layout import Layout, HYDE_DATA
  7from hyde.model import Config
  8from hyde.site import Site
  9from hyde.version import __version__
 10
 11from commando import (
 12    Application,
 13    command,
 14    store,
 15    subcommand,
 16    true,
 17    version
 18)
 19from commando.util import getLoggerWithConsoleHandler
 20from fswrap import FS, Folder
 21
 22HYDE_LAYOUTS = "HYDE_LAYOUTS"
 23
 24
 25class Engine(Application):
 26
 27    def __init__(self, raise_exceptions=False):
 28        logger = getLoggerWithConsoleHandler('hyde')
 29        super(Engine, self).__init__(
 30            raise_exceptions=raise_exceptions,
 31            logger=logger
 32        )
 33
 34    @command(description='hyde - a python static website generator',
 35             epilog='Use %(prog)s {command} -h to get help'
 36                    'on individual commands')
 37    @true('-v', '--verbose', help="Show detailed information in console")
 38    @true('-x', '--raise-exceptions', default=None,
 39          help="Don't handle exceptions.")
 40    @version('--version', version='%(prog)s ' + __version__)
 41    @store('-s', '--sitepath', default='.', help="Location of the hyde site")
 42    def main(self, args):
 43        """
 44        Will not be executed. A sub command is required. This function exists
 45        to provide common parameters for the subcommands and some generic stuff
 46        like version and metadata
 47        """
 48        sitepath = Folder(args.sitepath).fully_expanded_path
 49        if args.raise_exceptions in (True, False):
 50            self.raise_exceptions = args.raise_exceptions
 51        return Folder(sitepath)
 52
 53    @subcommand('create', help='Create a new hyde site.')
 54    @store('-l', '--layout', default='basic', help='Layout for the new site')
 55    @true('-f', '--force', default=False, dest='overwrite',
 56          help='Overwrite the current site if it exists')
 57    def create(self, args):
 58        """
 59        The create command. Creates a new site from the template at the given
 60        sitepath.
 61        """
 62        sitepath = self.main(args)
 63        markers = ['content', 'layout', 'site.yaml']
 64        exists = any((FS(sitepath.child(item)).exists for item in markers))
 65
 66        if exists and not args.overwrite:
 67            raise HydeException(
 68                "The given site path [%s] already contains a hyde site."
 69                " Use -f to overwrite." % sitepath)
 70        layout = Layout.find_layout(args.layout)
 71        self.logger.info(
 72            "Creating site at [%s] with layout [%s]" % (sitepath, layout))
 73        if not layout or not layout.exists:
 74            raise HydeException(
 75                "The given layout is invalid. Please check if you have the"
 76                " `layout` in the right place and the environment variable(%s)"
 77                " has been setup properly if you are using custom path for"
 78                " layouts" % HYDE_DATA)
 79        layout.copy_contents_to(args.sitepath)
 80        self.logger.info("Site creation complete")
 81
 82    @subcommand('gen', help='Generate the site')
 83    @store('-c', '--config-path', default='site.yaml', dest='config',
 84           help='The configuration used to generate the site')
 85    @store('-d', '--deploy-path', dest='deploy', default=None,
 86           help='Where should the site be generated?')
 87    @true('-r', '--regen', dest='regen', default=False,
 88          help='Regenerate the whole site, including unchanged files')
 89    def gen(self, args):
 90        """
 91        The generate command. Generates the site at the given
 92        deployment directory.
 93        """
 94        sitepath = self.main(args)
 95        site = self.make_site(sitepath, args.config, args.deploy)
 96        from hyde.generator import Generator
 97        gen = Generator(site)
 98        incremental = True
 99        if args.regen:
100            self.logger.info("Regenerating the site...")
101            incremental = False
102        gen.generate_all(incremental=incremental)
103        self.logger.info("Generation complete.")
104
105    @subcommand('serve', help='Serve the website')
106    @store('-a', '--address', default='localhost', dest='address',
107           help='The address where the website must be served from.')
108    @store('-p', '--port', type=int, default=8080, dest='port',
109           help='The port where the website must be served from.')
110    @store('-c', '--config-path', default='site.yaml', dest='config',
111           help='The configuration used to generate the site')
112    @store('-d', '--deploy-path', dest='deploy', default=None,
113           help='Where should the site be generated?')
114    def serve(self, args):
115        """
116        The serve command. Serves the site at the given
117        deployment directory, address and port. Regenerates
118        the entire site or specific files based on the request.
119        """
120        sitepath = self.main(args)
121        site = self.make_site(sitepath, args.config, args.deploy)
122        from hyde.server import HydeWebServer
123        server = HydeWebServer(site, args.address, args.port)
124        self.logger.info(
125            "Starting webserver at [%s]:[%d]", args.address, args.port)
126        try:
127            server.serve_forever()
128        except (KeyboardInterrupt, SystemExit):
129            self.logger.info("Received shutdown request. Shutting down...")
130            server.shutdown()
131            self.logger.info("Server successfully stopped")
132            exit()
133
134    @subcommand('publish', help='Publish the website')
135    @store('-c', '--config-path', default='site.yaml', dest='config',
136           help='The configuration used to generate the site')
137    @store('-p', '--publisher', dest='publisher', default='default',
138           help='Points to the publisher configuration.')
139    @store('-m', '--message', dest='message',
140           help='Optional message.')
141    def publish(self, args):
142        """
143        Publishes the site based on the configuration from the `target`
144        parameter.
145        """
146        sitepath = self.main(args)
147        site = self.make_site(sitepath, args.config)
148        from hyde.publisher import Publisher
149        publisher = Publisher.load_publisher(site,
150                                             args.publisher,
151                                             args.message)
152        publisher.publish()
153
154    def make_site(self, sitepath, config, deploy=None):
155        """
156        Creates a site object from the given sitepath and the config file.
157        """
158        config = Config(sitepath, config_file=config)
159        if deploy:
160            config.deploy_root = deploy
161        return Site(sitepath, config)