Esempio n. 1
0
class Clay(object):

    def __init__(self, base_dir, settings=None, source_dir=config.SOURCE_DIR):
        if os.path.isfile(base_dir):
            base_dir = os.path.abspath(os.path.dirname(base_dir))
        self.base_dir = base_dir
        self.source_dir = utils.make_dirs(base_dir, source_dir)
        self.build_dir = os.path.join(base_dir, config.BUILD_DIR)

        settings = settings or {}
        self.settings = Settings(config.default_settings, settings,
            case_insensitive=True)

        theme_prefix = self.settings.get('theme_prefix', '').rstrip('/')
        if theme_prefix:
            theme_prefix += '/'
        self.settings['theme_prefix'] = theme_prefix

        views_ignore = self.settings.get('views_ignore', [])
        self.settings['views_ignore'] = tuple(views_ignore)

        self.app = Shake(config.app_settings)
        self._make_render()
        self._enable_pre_processors()
        self._add_urls()

    def _make_render(self):
        loader = ChoiceLoader([
            FileSystemLoader(self.source_dir),
            PackageLoader('clay', config.SOURCE_DIR),
        ])
        self.render = Render(loader=loader)
        self.render.set_filter('json', utils.filter_to_json)

    def _enable_pre_processors(self):
        ext_trans = {}
        processors = self.settings.pre_processors

        for name in processors:
            pr = globals().get('p_' + name)
            if pr and pr.enabled:
                pr.add_extensions(self)
                for ext in pr.extensions_in:
                    ext_trans[ext] = pr.extension_out

        self.ext_trans = ext_trans

    def _add_urls(self):
        self.app.add_urls([
            Rule('/', self.render_view),
            Rule('/<path:path>', self.render_view),
        ])

    def _normalize_path(self, path):
        if '..' in path:
            return self.not_found()
        path = path.strip('/')
        is_dir = os.path.isdir(os.path.join(self.source_dir, path))
        if is_dir:
            path += '/'
        if not path or is_dir:
            path += 'index.html'
        return path

    def _translate_ext(self, old_ext):
        return self.ext_trans.get(old_ext, old_ext)

    def _get_alternative(self, path):
        path = path.strip('/')
        fname, ext = os.path.splitext(path)
        fullpath = os.path.join(config.DEFAULT_TEMPLATES, path)
        if os.path.exists(fullpath):
            return ext, path, fullpath
        
        if path != 'index.html':
            return None, None, None

        pdir = os.path.join(self.source_dir, fname + '.*')
        files = glob.glob(pdir)
        if files:
            fullpath = files[0]
            path = fullpath.replace(self.source_dir, '')
            _, ext = os.path.splitext(path)
            return ext, path, fullpath

        return None, None, None

    def _post_process(self, html):
        html = utils.to_unicode(html)
        processors = self.settings.post_processors

        for name in processors:
            pp = globals().get('pp_' + name)
            if pp and pp.enabled:
                html = pp.process(html)

        return html

    def run(self, host=None, port=None):
        host = host if host is not None else self.settings.HOST
        port = port if port is not None else self.settings.PORT
        try:
            port = int(port)
        except Exception:
            port = self.settings.PORT
        ips = [ip for ip in socket.gethostbyname_ex(socket.gethostname())[2]
            if not ip.startswith("127.")][:1]
        if ips:
            print ' * Your local IP is:', ips[0]
        try:
            self.app.run(host=host, port=port)
        except socket.error, e:
            print e
Esempio n. 2
0
class Clay(object):

    def __init__(self, base_dir, settings=None, source_dir=SOURCE_DIR):
        if os.path.isfile(base_dir):
            base_dir = os.path.abspath(os.path.dirname(base_dir))
        self.base_dir = base_dir
        self.settings = settings
        self.source_dir = utils.make_dirs(base_dir, source_dir)
        self.build_dir = os.path.join(base_dir, BUILD_DIR)

        self.settings = Settings(default_settings, settings,
            case_insensitive=True)
        
        self.app = Shake(self._get_urls())
        self.render = Render(self.source_dir, self.settings)
    
    def run(self, host=None, port=None):
        host = host or self.settings.host
        port = port or self.settings.port
        return self.app.run(host, port)
    
    def build(self):
        """Generates a static version of the site.
        """
        print '\nGenerating views...\n', '-' * 20
        self.build_views()
        print '\nDone!\n'
    
    def test_client(self):
        return self.app.test_client()
    
    def _get_urls(self):
        return [
            Rule('/', self.render_view),
            Rule('/<path:path>', self.render_view),
        ]
    
    def _normalize_path(self, path):
        if '..' in path:
            return self.not_found()
        path = path.strip('/')
        is_dir = os.path.isdir(os.path.join(self.source_dir, path))
        if is_dir:
            path += '/'
        if not path or is_dir:
            path += 'index.html'
        return path
    
    def render_view(self, request, path=''):
        """Default controller.
        Render the template at `path` guessing it's mimetype.
        """
        path = self._normalize_path(path)
        try:
            content, ext = self.render(path, **self.settings)
            mimetype = mimetypes.guess_type('a' + ext)[0] or 'text/plain'
        except TemplateNotFound:
            return self.not_found()
        if content:
            return Response(content, mimetype=mimetype)
        
        fullpath = os.path.join(self.source_dir, path)
        if not os.path.isfile(fullpath):
            return self.not_found() 
        return send_file(request, fullpath)
    
    def build_views(self):
        processed = []
        views = []

        def callback(relpath_in):
            print relpath_in
            fn, old_ext = os.path.splitext(relpath_in)
            content, ext = self.render(relpath_in, **self.settings)
            relpath_out = '%s%s' % (fn, ext)
            path_in = os.path.join(self.source_dir, relpath_in)
            path_out = utils.make_dirs(self.build_dir, relpath_out)

            if not content:
                return shutil.copy2(path_in, path_out)
            if ext == '.html':
                return views.append([relpath_in, path_out, content])
            if ext != old_ext:
                processed.append([relpath_in, relpath_out])
            utils.make_file(path_out, content)
            return
        
        utils.walk_dir(self.source_dir, callback, IGNORE)
        rx_processed = utils.get_processed_regex(processed)
        views_list = []

        for relpath_in, path_out, content in views:
            content = utils.absolute_to_relative(content, relpath_in)
            content = utils.replace_processed_names(content, rx_processed)
            utils.make_file(path_out, content)
            views_list.append(relpath_in.decode('utf8'))
        
        self.build_views_list(views_list)
    
    def build_views_list(self, views):
        ignore = self.settings.views_list_ignore
        ignore.append(VIEWS_INDEX)

        views = [
            (
                v,
                ' / '.join(v.split('/')),
                utils.get_file_mdate(os.path.join(self.source_dir, v)),
            ) \
            for v in views \
                if v not in ignore and not v.startswith(IGNORE)
            ]
        content, mimetype = self.render(VIEWS_INDEX, views=views)
        final_path = utils.make_dirs(self.build_dir, VIEWS_INDEX)
        utils.make_file(final_path, content)
    
    def not_found(self):
        content, ext = self.render('notfound.html')
        resp = Response(content)
        resp.status_code = 404
        resp.mimetype = 'text/html'
        return resp