app_cfg.py
213 lines
| 8.0 KiB
| text/x-python
|
PythonLexer
|
r6514 | # -*- coding: utf-8 -*- | ||
# This program is free software: you can redistribute it and/or modify | ||||
# it under the terms of the GNU General Public License as published by | ||||
# the Free Software Foundation, either version 3 of the License, or | ||||
# (at your option) any later version. | ||||
# | ||||
# This program is distributed in the hope that it will be useful, | ||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
# GNU General Public License for more details. | ||||
# | ||||
# You should have received a copy of the GNU General Public License | ||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
|
r6522 | """ | ||
Global configuration file for TurboGears2 specific settings in Kallithea. | ||||
|
r6514 | |||
|
r6522 | This file complements the .ini file. | ||
""" | ||||
|
r7718 | import logging | ||
import os | ||||
|
r6514 | import platform | ||
|
r7718 | import sys | ||
|
r6514 | |||
|
r7718 | import alembic.config | ||
import mercurial | ||||
|
r6522 | import tg | ||
|
r7718 | from alembic.migration import MigrationContext | ||
from alembic.script.base import ScriptDirectory | ||||
from sqlalchemy import create_engine | ||||
|
r6522 | from tg.configuration import AppConfig | ||
from tg.support.converters import asbool | ||||
|
r6514 | |||
|
r7657 | import kallithea.lib.locale | ||
|
r7718 | import kallithea.model.base | ||
|
r7876 | import kallithea.model.meta | ||
|
r7718 | from kallithea.lib.middleware.https_fixup import HttpsFixup | ||
|
r7620 | from kallithea.lib.middleware.permanent_repo_url import PermanentRepoUrl | ||
|
r6522 | from kallithea.lib.middleware.simplegit import SimpleGit | ||
from kallithea.lib.middleware.simplehg import SimpleHg | ||||
|
r7793 | from kallithea.lib.middleware.wrapper import RequestWrapper | ||
|
r7719 | from kallithea.lib.utils import check_git_version, load_rcextensions, make_ui, set_app_settings, set_indexer_config, set_vcs_config | ||
|
r6522 | from kallithea.lib.utils2 import str2bool | ||
|
r6514 | |||
|
r6522 | |||
|
r6556 | log = logging.getLogger(__name__) | ||
|
r6522 | |||
class KallitheaAppConfig(AppConfig): | ||||
# Note: AppConfig has a misleading name, as it's not the application | ||||
# configuration, but the application configurator. The AppConfig values are | ||||
# used as a template to create the actual configuration, which might | ||||
# overwrite or extend the one provided by the configurator template. | ||||
# To make it clear, AppConfig creates the config and sets into it the same | ||||
# values that AppConfig itself has. Then the values from the config file and | ||||
# gearbox options are loaded and merged into the configuration. Then an | ||||
# after_init_config(conf) method of AppConfig is called for any change that | ||||
# might depend on options provided by configuration files. | ||||
def __init__(self): | ||||
super(KallitheaAppConfig, self).__init__() | ||||
self['package'] = kallithea | ||||
self['prefer_toscawidgets2'] = False | ||||
self['use_toscawidgets'] = False | ||||
self['renderers'] = [] | ||||
# Enable json in expose | ||||
self['renderers'].append('json') | ||||
|
r6515 | |||
|
r6522 | # Configure template rendering | ||
self['renderers'].append('mako') | ||||
self['default_renderer'] = 'mako' | ||||
self['use_dotted_templatenames'] = False | ||||
# Configure Sessions, store data as JSON to avoid pickle security issues | ||||
self['session.enabled'] = True | ||||
self['session.data_serializer'] = 'json' | ||||
# Configure the base SQLALchemy Setup | ||||
self['use_sqlalchemy'] = True | ||||
self['model'] = kallithea.model.base | ||||
self['DBSession'] = kallithea.model.meta.Session | ||||
# Configure App without an authentication backend. | ||||
self['auth_backend'] = None | ||||
|
r6515 | |||
|
r6522 | # Use custom error page for these errors. By default, Turbogears2 does not add | ||
# 400 in this list. | ||||
# Explicitly listing all is considered more robust than appending to defaults, | ||||
# in light of possible future framework changes. | ||||
self['errorpage.status_codes'] = [400, 401, 403, 404] | ||||
|
r6515 | |||
|
r6522 | # Disable transaction manager -- currently Kallithea takes care of transactions itself | ||
self['tm.enabled'] = False | ||||
|
r8012 | # Set the i18n source language so TG doesn't search beyond 'en' in Accept-Language. | ||
# Don't force the default here if configuration force something else. | ||||
if not self.get('i18n.lang'): | ||||
self['i18n.lang'] = 'en' | ||||
|
r6789 | |||
|
r6522 | base_config = KallitheaAppConfig() | ||
|
r6524 | # DebugBar, a debug toolbar for TurboGears2. | ||
# (https://github.com/TurboGears/tgext.debugbar) | ||||
# To enable it, install 'tgext.debugbar' and 'kajiki', and run Kallithea with | ||||
# 'debug = true' (not in production!) | ||||
# See the Kallithea documentation for more information. | ||||
try: | ||||
from tgext.debugbar import enable_debugbar | ||||
import kajiki # only to check its existence | ||||
except ImportError: | ||||
pass | ||||
else: | ||||
base_config['renderers'].append('kajiki') | ||||
enable_debugbar(base_config) | ||||
|
r6522 | def setup_configuration(app): | ||
config = app.config | ||||
|
r6514 | |||
|
r7657 | if not kallithea.lib.locale.current_locale_is_valid(): | ||
|
r7299 | log.error("Terminating ...") | ||
sys.exit(1) | ||||
|
r7249 | # Mercurial sets encoding at module import time, so we have to monkey patch it | ||
hgencoding = config.get('hgencoding') | ||||
if hgencoding: | ||||
mercurial.encoding.encoding = hgencoding | ||||
|
r6556 | if config.get('ignore_alembic_revision', False): | ||
log.warn('database alembic revision checking is disabled') | ||||
else: | ||||
dbconf = config['sqlalchemy.url'] | ||||
alembic_cfg = alembic.config.Config() | ||||
alembic_cfg.set_main_option('script_location', 'kallithea:alembic') | ||||
alembic_cfg.set_main_option('sqlalchemy.url', dbconf) | ||||
script_dir = ScriptDirectory.from_config(alembic_cfg) | ||||
available_heads = sorted(script_dir.get_heads()) | ||||
engine = create_engine(dbconf) | ||||
with engine.connect() as conn: | ||||
context = MigrationContext.configure(conn) | ||||
current_heads = sorted(str(s) for s in context.get_current_heads()) | ||||
if current_heads != available_heads: | ||||
log.error('Failed to run Kallithea:\n\n' | ||||
'The database version does not match the Kallithea version.\n' | ||||
'Please read the documentation on how to upgrade or downgrade the database.\n' | ||||
'Current database version id(s): %s\n' | ||||
'Expected database version id(s): %s\n' | ||||
'If you are a developer and you know what you are doing, you can add `ignore_alembic_revision = True` ' | ||||
'to your .ini file to skip the check.\n' % (' '.join(current_heads), ' '.join(available_heads))) | ||||
sys.exit(1) | ||||
|
r6514 | # store some globals into kallithea | ||
|
r7713 | kallithea.CELERY_ON = str2bool(config.get('use_celery')) | ||
kallithea.CELERY_EAGER = str2bool(config.get('celery.always.eager')) | ||||
|
r6522 | kallithea.CONFIG = config | ||
|
r6514 | |||
load_rcextensions(root_path=config['here']) | ||||
|
r7958 | repos_path = make_ui().configitems(b'paths')[0][1] | ||
|
r6514 | config['base_path'] = repos_path | ||
set_app_settings(config) | ||||
instance_id = kallithea.CONFIG.get('instance_id', '*') | ||||
if instance_id == '*': | ||||
instance_id = '%s-%s' % (platform.uname()[1], os.getpid()) | ||||
kallithea.CONFIG['instance_id'] = instance_id | ||||
|
r6522 | # update kallithea.CONFIG with the meanwhile changed 'config' | ||
kallithea.CONFIG.update(config) | ||||
|
r6514 | |||
|
r6522 | # configure vcs and indexer libraries (they are supposed to be independent | ||
# as much as possible and thus avoid importing tg.config or | ||||
# kallithea.CONFIG). | ||||
|
r6514 | set_vcs_config(kallithea.CONFIG) | ||
set_indexer_config(kallithea.CONFIG) | ||||
check_git_version() | ||||
|
r7876 | kallithea.model.meta.Session.remove() | ||
|
r6789 | |||
|
r8040 | tg.hooks.register('configure_new_app', setup_configuration) | ||
|
r6515 | |||
|
r6522 | def setup_application(app): | ||
config = app.config | ||||
|
r6515 | |||
|
r6522 | # we want our low level middleware to get to the request ASAP. We don't | ||
# need any stack middleware in them - especially no StatusCodeRedirect buffering | ||||
app = SimpleHg(app, config) | ||||
app = SimpleGit(app, config) | ||||
|
r6515 | |||
|
r6522 | # Enable https redirects based on HTTP_X_URL_SCHEME set by proxy | ||
if any(asbool(config.get(x)) for x in ['https_fixup', 'force_https', 'use_htsts']): | ||||
app = HttpsFixup(app, config) | ||||
|
r7620 | |||
app = PermanentRepoUrl(app, config) | ||||
|
r7793 | |||
# Optional and undocumented wrapper - gives more verbose request/response logging, but has a slight overhead | ||||
if str2bool(config.get('use_wsgi_wrapper')): | ||||
app = RequestWrapper(app, config) | ||||
|
r6522 | return app | ||
|
r6515 | |||
|
r6789 | |||
|
r8040 | tg.hooks.register('before_config', setup_application) | ||