Files @ 5dfaa9f1fdb2
Branch filter:

Location: kallithea/scripts/generate-ini.py

Mads Kiilerich
templates: disable special mako error handler - ironically this gives better stack traces

Errors in templates could give truncated stack traces pointing at the mako
error handler:

...
File '.../kallithea/kallithea/controllers/files.py', line 202 in index
return render('files/files.html')
File '.../kallithea-venv/lib/python2.7/site-packages/pylons/templating.py', line 244 in render_mako
cache_type=cache_type, cache_expire=cache_expire)
File '.../kallithea-venv/lib/python2.7/site-packages/pylons/templating.py', line 219 in cached_template
return render_func()
File '.../kallithea-venv/lib/python2.7/site-packages/pylons/templating.py', line 241 in render_template
return literal(template.render_unicode(**globs))
File '.../kallithea-venv/lib/python2.7/site-packages/mako/template.py', line 452 in render_unicode
as_unicode=True)
File '.../kallithea-venv/lib/python2.7/site-packages/mako/runtime.py', line 803 in _render
**_kwargs_for_callable(callable_, data))
File '.../kallithea-venv/lib/python2.7/site-packages/mako/runtime.py', line 835 in _render_context
_exec_template(inherit, lclcontext, args=args, kwargs=kwargs)
File '.../kallithea-venv/lib/python2.7/site-packages/mako/runtime.py', line 855 in _exec_template
_render_error(template, context, compat.exception_as())
File '.../kallithea-venv/lib/python2.7/site-packages/mako/runtime.py', line 864 in _render_error
result = template.error_handler(context, error)
File '.../kallithea-venv/lib/python2.7/site-packages/pylons/error.py', line 22 in handle_mako_error
raise (exc, None, sys.exc_info()[2])
AttributeError: 'tuple' object has no attribute 'node'

Without the mako error handler we get a full and useful stack trace - including
calls in generated but readable .html.py files.

File '.../kallithea/kallithea/controllers/files.py', line 202 in index
return render('files/files.html')
File '.../kallithea-venv/lib/python2.7/site-packages/pylons/templating.py', line 244 in render_mako
cache_type=cache_type, cache_expire=cache_expire)
File '.../kallithea-venv/lib/python2.7/site-packages/pylons/templating.py', line 219 in cached_template
return render_func()
File '.../kallithea-venv/lib/python2.7/site-packages/pylons/templating.py', line 241 in render_template
return literal(template.render_unicode(**globs))
File '.../kallithea-venv/lib/python2.7/site-packages/mako/template.py', line 452 in render_unicode
as_unicode=True)
File '.../kallithea-venv/lib/python2.7/site-packages/mako/runtime.py', line 803 in _render
**_kwargs_for_callable(callable_, data))
File '.../kallithea-venv/lib/python2.7/site-packages/mako/runtime.py', line 835 in _render_context
_exec_template(inherit, lclcontext, args=args, kwargs=kwargs)
File '.../kallithea-venv/lib/python2.7/site-packages/mako/runtime.py', line 860 in _exec_template
callable_(context, *args, **kwargs)
File '.../data/templates/base/root.html.py', line 219 in render_body
__M_writer(escape(next.body()))
File '.../data/templates/base/base.html.py', line 57 in render_body
__M_writer(escape(next.main()))
File '.../data/templates/files/files.html.py', line 121 in render_main
runtime._include_file(context, u'files_ypjax.html', _template_uri)
File '.../kallithea-venv/lib/python2.7/site-packages/mako/runtime.py', line 730 in _include_file
callable_(ctx, **_kwargs_for_include(callable_, context._data, **kwargs))
File '.../data/templates/files/files_ypjax.html.py', line 57 in render_body
runtime._include_file(context, u'files_source.html', _template_uri)
File '.../kallithea-venv/lib/python2.7/site-packages/mako/runtime.py', line 730 in _include_file
callable_(ctx, **_kwargs_for_include(callable_, context._data, **kwargs))
File '.../data/templates/files/files_source.html.py', line 117 in render_body
__M_writer(escape(h.pygmentize_annotation(c.repo_name,c.file,linenos=True,anchorlinenos=True,lineanchors='L',cssclass="code-highlight")))
File '.../kallithea/kallithea/lib/helpers.py', line 360 in pygmentize_annotation
return literal(markup_whitespace(annotate_highlight(filenode, url_func(repo_name), **kwargs)))
File '.../kallithea/kallithea/lib/annotate.py', line 57 in annotate_highlight
highlighted = highlight(filenode.content, lexer, formatter)
File '.../kallithea-venv/lib/python2.7/site-packages/pygments/__init__.py', line 87 in highlight
return format(lex(code, lexer), formatter, outfile)
File '.../kallithea-venv/lib/python2.7/site-packages/pygments/__init__.py', line 66 in format
formatter.format(tokens, realoutfile)
File '.../kallithea-venv/lib/python2.7/site-packages/pygments/formatter.py', line 95 in format
return self.format_unencoded(tokensource, outfile)
File '.../kallithea-venv/lib/python2.7/site-packages/pygments/formatters/html.py', line 850 in format_unencoded
for t, piece in source:
File '.../kallithea/kallithea/lib/annotate.py', line 168 in _wrap_tablelinenos
for el in self.filenode.annotate))
File '.../kallithea/kallithea/lib/annotate.py', line 167 in <genexpr>
annotate = ''.join((self.annotate_from_changeset(el[2]())
File '.../kallithea/kallithea/lib/vcs/backends/hg/changeset.py', line 273 in get_file_annotate
sha = hex(annotate_data[0].node())
#!/usr/bin/env python2
"""
Based on kallithea/bin/template.ini.mako, generate
  kallithea/config/deployment.ini_tmpl
  development.ini
  kallithea/tests/test.ini
"""

import re

makofile = 'kallithea/bin/template.ini.mako'

# the mako conditionals used in all other ini files and templates
selected_mako_conditionals = set([
    "database_engine == 'sqlite'",
    "http_server == 'waitress'",
    "error_aggregation_service == 'errormator'",
    "error_aggregation_service == 'sentry'",
])

# the mako variables used in all other ini files and templates
mako_variable_values = {
    'host': '127.0.0.1',
    'port': '5000',
    'here': '%(here)s',
    'uuid()': '${app_instance_uuid}',
}

# files to be generated from the mako template
ini_files = [
    ('kallithea/config/deployment.ini_tmpl',
        '''
        Kallithea - Example config

        The %(here)s variable will be replaced with the parent directory of this file
        ''',
        {}, # exactly the same settings as template.ini.mako
    ),
    ('kallithea/tests/test.ini',
        '''
        Kallithea - config for tests:
        initial_repo_scan = true
        sqlalchemy and kallithea_test.sqlite
        custom logging

        The %(here)s variable will be replaced with the parent directory of this file
        ''',
        {
            '[server:main]': {
                'port': '4999',
            },
            '[app:main]': {
                'initial_repo_scan': 'true',
                'app_instance_uuid': 'test',
                'show_revision_number': 'true',
                'beaker.cache.sql_cache_short.expire': '1',
                'beaker.session.secret': '{74e0cd75-b339-478b-b129-07dd221def1f}',
                'sqlalchemy.db1.url': 'sqlite:///%(here)s/kallithea_test.sqlite',
            },
            '[logger_root]': {
                'level': 'DEBUG',
            },
            '[logger_sqlalchemy]': {
                'level': 'ERROR',
                'handlers': 'console',
            },
            '[handler_console]': {
                'level': 'NOTSET',
            },
        },
    ),
    ('development.ini',
        '''
        Kallithea - Development config:
        listening on *:5000
        sqlite and kallithea.db
        initial_repo_scan = true
        set debug = true
        verbose and colorful logging

        The %(here)s variable will be replaced with the parent directory of this file
        ''',
        {
            '[server:main]': {
                'host': '0.0.0.0',
            },
            '[app:main]': {
                'initial_repo_scan': 'true',
                'set debug': 'true',
                'app_instance_uuid': 'development-not-secret',
                'beaker.session.secret': 'development-not-secret',
            },
            '[handler_console]': {
                'level': 'DEBUG',
                'formatter': 'color_formatter',
            },
            '[handler_console_sql]': {
                'level': 'DEBUG',
                'formatter': 'color_formatter_sql',
            },
        },
    ),
]


def main():
    # make sure all mako lines starting with '#' (the '##' comments) are marked up as <text>
    print 'reading:', makofile
    mako_org = file(makofile).read()
    mako_no_text_markup = re.sub(r'</?%text>', '', mako_org)
    mako_marked_up = re.sub(r'\n(##.*)', r'\n<%text>\1</%text>', mako_no_text_markup, flags=re.MULTILINE)
    if mako_marked_up != mako_org:
        print 'writing:', makofile
        file(makofile, 'w').write(mako_marked_up)

    # select the right mako conditionals for the other less sophisticated formats
    def sub_conditionals(m):
        """given a %if...%endif match, replace with just the selected
        conditional sections enabled and the rest as comments
        """
        conditional_lines = m.group(1)
        def sub_conditional(m):
            """given a conditional and the corresponding lines, return them raw
            or commented out, based on whether conditional is selected
            """
            criteria, lines = m.groups()
            if criteria not in selected_mako_conditionals:
                lines = '\n'.join((l if not l or l.startswith('#') else '#' + l) for l in lines.split('\n'))
            return lines
        conditional_lines = re.sub(r'^%(?:el)?if (.*):\n((?:^[^%\n].*\n|\n)*)',
            sub_conditional, conditional_lines, flags=re.MULTILINE)
        return conditional_lines
    mako_no_conditionals = re.sub(r'^(%if .*\n(?:[^%\n].*\n|%elif .*\n|\n)*)%endif\n',
        sub_conditionals, mako_no_text_markup, flags=re.MULTILINE)

    # expand mako variables
    def pyrepl(m):
        return mako_variable_values.get(m.group(1), m.group(0))
    mako_no_variables = re.sub(r'\${([^}]*)}', pyrepl, mako_no_conditionals)

    # remove utf-8 coding header
    base_ini = re.sub(r'^## -\*- coding: utf-8 -\*-\n', '', mako_no_variables)

    # create ini files
    for fn, desc, settings in ini_files:
        print 'updating:', fn
        ini_lines = re.sub(
            '# Kallithea - config file generated with kallithea-config *#\n',
            ''.join('# %-77s#\n' % l.strip() for l in desc.strip().split('\n')),
            base_ini)
        def process_section(m):
            """process a ini section, replacing values as necessary"""
            sectionname, lines = m.groups()
            if sectionname in settings:
                section_settings = settings[sectionname]
                def process_line(m):
                    """process a section line and update value if necessary"""
                    setting, value = m.groups()
                    line = m.group(0)
                    if setting in section_settings:
                        line = '%s = %s' % (setting, section_settings[setting])
                        if '$' not in value:
                            line = '#%s = %s\n%s' % (setting, value, line)
                    return line.rstrip()
                lines = re.sub(r'^([^#\n].*) = ?(.*)', process_line, lines, flags=re.MULTILINE)
            return sectionname + '\n' + lines
        ini_lines = re.sub(r'^(\[.*\])\n((?:(?:[^[\n].*)?\n)*)', process_section, ini_lines, flags=re.MULTILINE)
        file(fn, 'w').write(ini_lines)

if __name__ == '__main__':
    main()