Changeset - 488b52cad890
[Not reviewed]
stable
0 4 0
Wolfgang Scherer - 6 years ago 2019-12-29 17:35:13
Wolfgang.Scherer@gmx.de
Grafted from: feeb11b8ec9d
logging: always invoke fileConfig with '__file__' and 'here'

WSGI servers tend to provide '__file__' and 'here' as 'defaults' when invoking
fileConfig, so '%(here)s' string interpolation also can be used in logging
configuration.

Make sure we do the same when we initialize logging without using a WSGI server.

It is annoying to have to do this, and it will only in rare cases make any
difference ... but it seems like the best option.

Patch also modified by Mads Kiilerich.
4 files changed with 10 insertions and 5 deletions:
0 comments (0 inline, 0 general)
docs/setup.rst
Show inline comments
 
@@ -469,170 +469,170 @@ Here is a sample configuration file for 
 
            ServerName kallithea.example.com
 

	
 
            <Proxy *>
 
              # For Apache 2.4 and later:
 
              Require all granted
 

	
 
              # For Apache 2.2 and earlier, instead use:
 
              # Order allow,deny
 
              # Allow from all
 
            </Proxy>
 

	
 
            #important !
 
            #Directive to properly generate url (clone url) for Kallithea
 
            ProxyPreserveHost On
 

	
 
            #kallithea instance
 
            ProxyPass / http://127.0.0.1:5000/
 
            ProxyPassReverse / http://127.0.0.1:5000/
 

	
 
            #to enable https use line below
 
            #SetEnvIf X-Url-Scheme https HTTPS=1
 
    </VirtualHost>
 

	
 
Additional tutorial
 
http://pylonsbook.com/en/1.1/deployment.html#using-apache-to-proxy-requests-to-pylons
 

	
 
.. _apache_subdirectory:
 

	
 

	
 
Apache as subdirectory
 
----------------------
 

	
 
Apache subdirectory part:
 

	
 
.. code-block:: apache
 

	
 
    <Location /PREFIX >
 
      ProxyPass http://127.0.0.1:5000/PREFIX
 
      ProxyPassReverse http://127.0.0.1:5000/PREFIX
 
      SetEnvIf X-Url-Scheme https HTTPS=1
 
    </Location>
 

	
 
Besides the regular apache setup you will need to add the following line
 
into ``[app:main]`` section of your .ini file::
 

	
 
    filter-with = proxy-prefix
 

	
 
Add the following at the end of the .ini file::
 

	
 
    [filter:proxy-prefix]
 
    use = egg:PasteDeploy#prefix
 
    prefix = /PREFIX
 

	
 
then change ``PREFIX`` into your chosen prefix
 

	
 
.. _apache_mod_wsgi:
 

	
 

	
 
Apache with mod_wsgi
 
--------------------
 

	
 
Alternatively, Kallithea can be set up with Apache under mod_wsgi. For
 
that, you'll need to:
 

	
 
- Install mod_wsgi. If using a Debian-based distro, you can install
 
  the package libapache2-mod-wsgi::
 

	
 
    aptitude install libapache2-mod-wsgi
 

	
 
- Enable mod_wsgi::
 

	
 
    a2enmod wsgi
 

	
 
- Add global Apache configuration to tell mod_wsgi that Python only will be
 
  used in the WSGI processes and shouldn't be initialized in the Apache
 
  processes::
 

	
 
    WSGIRestrictEmbedded On
 

	
 
- Create a WSGI dispatch script, like the one below. Make sure you
 
  check that the paths correctly point to where you installed Kallithea
 
  and its Python Virtual Environment.
 

	
 
  .. code-block:: python
 

	
 
      import os
 
      os.environ['PYTHON_EGG_CACHE'] = '/srv/kallithea/.egg-cache'
 

	
 
      # sometimes it's needed to set the current dir
 
      os.chdir('/srv/kallithea/')
 

	
 
      import site
 
      site.addsitedir("/srv/kallithea/venv/lib/python2.7/site-packages")
 

	
 
      ini = '/srv/kallithea/my.ini'
 
      from logging.config import fileConfig
 
      fileConfig(ini)
 
      fileConfig(ini, {'__file__': ini, 'here': '/srv/kallithea'})
 
      from paste.deploy import loadapp
 
      application = loadapp('config:' + ini)
 

	
 
  Or using proper virtualenv activation:
 

	
 
  .. code-block:: python
 

	
 
      activate_this = '/srv/kallithea/venv/bin/activate_this.py'
 
      execfile(activate_this, dict(__file__=activate_this))
 

	
 
      import os
 
      os.environ['HOME'] = '/srv/kallithea'
 

	
 
      ini = '/srv/kallithea/kallithea.ini'
 
      from logging.config import fileConfig
 
      fileConfig(ini)
 
      fileConfig(ini, {'__file__': ini, 'here': '/srv/kallithea'})
 
      from paste.deploy import loadapp
 
      application = loadapp('config:' + ini)
 

	
 
- Add the necessary ``WSGI*`` directives to the Apache Virtual Host configuration
 
  file, like in the example below. Notice that the WSGI dispatch script created
 
  above is referred to with the ``WSGIScriptAlias`` directive.
 
  The default locale settings Apache provides for web services are often not
 
  adequate, with `C` as the default language and `ASCII` as the encoding.
 
  Instead, use the ``lang`` parameter of ``WSGIDaemonProcess`` to specify a
 
  suitable locale. See also the :ref:`overview` section and the
 
  `WSGIDaemonProcess documentation`_.
 

	
 
  Apache will by default run as a special Apache user, on Linux systems
 
  usually ``www-data`` or ``apache``. If you need to have the repositories
 
  directory owned by a different user, use the user and group options to
 
  WSGIDaemonProcess to set the name of the user and group.
 

	
 
  Once again, check that all paths are correctly specified.
 

	
 
  .. code-block:: apache
 

	
 
      WSGIDaemonProcess kallithea processes=5 threads=1 maximum-requests=100 \
 
          python-home=/srv/kallithea/venv lang=C.UTF-8
 
      WSGIProcessGroup kallithea
 
      WSGIScriptAlias / /srv/kallithea/dispatch.wsgi
 
      WSGIPassAuthorization On
 

	
 
  Or if using a dispatcher WSGI script with proper virtualenv activation:
 

	
 
  .. code-block:: apache
 

	
 
      WSGIDaemonProcess kallithea processes=5 threads=1 maximum-requests=100 lang=en_US.utf8
 
      WSGIProcessGroup kallithea
 
      WSGIScriptAlias / /srv/kallithea/dispatch.wsgi
 
      WSGIPassAuthorization On
 

	
 

	
 
Other configuration files
 
-------------------------
 

	
 
A number of `example init.d scripts`__ can be found in
 
the ``init.d`` directory of the Kallithea source.
 

	
 
.. __: https://kallithea-scm.org/repos/kallithea/files/tip/init.d/ .
 

	
 

	
 
.. _virtualenv: http://pypi.python.org/pypi/virtualenv
 
.. _python: http://www.python.org/
 
.. _Python regular expression documentation: https://docs.python.org/2/library/re.html
 
.. _Mercurial: https://www.mercurial-scm.org/
 
.. _Celery: http://celeryproject.org/
 
.. _Celery documentation: http://docs.celeryproject.org/en/latest/getting-started/index.html
 
.. _RabbitMQ: http://www.rabbitmq.com/
 
.. _Redis: http://redis.io/
 
.. _mercurial-server: http://www.lshift.net/mercurial-server.html
 
.. _PublishingRepositories: https://www.mercurial-scm.org/wiki/PublishingRepositories
 
.. _WSGIDaemonProcess documentation: https://modwsgi.readthedocs.io/en/develop/configuration-directives/WSGIDaemonProcess.html
kallithea/alembic/env.py
Show inline comments
 
# -*- 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/>.
 

	
 
# Alembic migration environment (configuration).
 

	
 
import logging
 
from logging.config import fileConfig
 

	
 
from alembic import context
 
from sqlalchemy import engine_from_config, pool
 

	
 
from kallithea.model import db
 

	
 

	
 
# The alembic.config.Config object, which wraps the current .ini file.
 
config = context.config
 

	
 
# Default to use the main Kallithea database string in [app:main].
 
# For advanced uses, this can be overridden by specifying an explicit
 
# [alembic] sqlalchemy.url.
 
database_url = (
 
    config.get_main_option('sqlalchemy.url') or
 
    config.get_section_option('app:main', 'sqlalchemy.url')
 
)
 

	
 
# Configure default logging for Alembic. (This can be overriden by the
 
# config file, but usually isn't.)
 
logging.getLogger('alembic').setLevel(logging.INFO)
 

	
 
# Setup Python loggers based on the config file provided to the alembic
 
# command. If we're being invoked via the Alembic API (presumably for
 
# stamping during "kallithea-cli db-create"), config_file_name is not available,
 
# and loggers are assumed to already have been configured.
 
if config.config_file_name:
 
    fileConfig(config.config_file_name, disable_existing_loggers=False)
 
    fileConfig(config.config_file_name,
 
        {'__file__': config.config_file_name, 'here': os.path.dirname(config.config_file_name)},
 
        disable_existing_loggers=False)
 

	
 

	
 
def include_in_autogeneration(object, name, type, reflected, compare_to):
 
    """Filter changes subject to autogeneration of migrations. """
 

	
 
    # Don't include changes to sqlite_sequence.
 
    if type == 'table' and name == 'sqlite_sequence':
 
        return False
 

	
 
    return True
 

	
 

	
 
def run_migrations_offline():
 
    """Run migrations in 'offline' (--sql) mode.
 

	
 
    This produces an SQL script instead of directly applying the changes.
 
    Some migrations may not run in offline mode.
 
    """
 
    context.configure(
 
        url=database_url,
 
        literal_binds=True,
 
    )
 

	
 
    with context.begin_transaction():
 
        context.run_migrations()
 

	
 

	
 
def run_migrations_online():
 
    """Run migrations in 'online' mode.
 

	
 
    Connects to the database and directly applies the necessary
 
    migrations.
 
    """
 
    cfg = config.get_section(config.config_ini_section)
 
    cfg['sqlalchemy.url'] = database_url
 
    connectable = engine_from_config(
 
        cfg,
 
        prefix='sqlalchemy.',
 
        poolclass=pool.NullPool)
 

	
 
    with connectable.connect() as connection:
 
        context.configure(
 
            connection=connection,
 

	
 
            # Support autogeneration of migration scripts based on "diff" between
 
            # current database schema and kallithea.model.db schema.
 
            target_metadata=db.Base.metadata,
 
            include_object=include_in_autogeneration,
 
            render_as_batch=True, # batch mode is needed for SQLite support
 
        )
 

	
 
        with context.begin_transaction():
 
            context.run_migrations()
 

	
 

	
 
if context.is_offline_mode():
 
    run_migrations_offline()
 
else:
 
    run_migrations_online()
kallithea/bin/kallithea_cli_base.py
Show inline comments
 
# -*- 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/>.
 

	
 
import cStringIO
 
import functools
 
import logging.config
 
import os
 
import re
 
import sys
 

	
 
import click
 
import paste.deploy
 

	
 
import kallithea
 

	
 

	
 
# kallithea_cli is usually invoked through the 'kallithea-cli' wrapper script
 
# that is installed by setuptools, as specified in setup.py console_scripts
 
# entry_points. The script will be using the right virtualenv (if any), and for
 
# Unix, it will contain #! pointing at the right python executable. The script
 
# also makes sure sys.argv[0] points back at the script path, and that is what
 
# can be used to invoke 'kallithea-cli' later.
 
kallithea_cli_path = sys.argv[0]
 

	
 

	
 
def read_config(ini_file_name, strip_section_prefix):
 
    """Read ini_file_name content, and for all sections like '[X:Y]' where X is
 
    strip_section_prefix, replace the section name with '[Y]'."""
 

	
 
    def repl(m):
 
        if m.group(1) == strip_section_prefix:
 
            return '[%s]' % m.group(2)
 
        return m.group(0)
 

	
 
    with open(ini_file_name) as f:
 
        return re.sub(r'^\[([^:]+):(.*)]', repl, f.read(), flags=re.MULTILINE)
 

	
 

	
 
# This placeholder is the main entry point for the kallithea-cli command
 
@click.group(context_settings=dict(help_option_names=['-h', '--help']))
 
def cli():
 
    """Various commands to manage a Kallithea instance."""
 

	
 
def register_command(config_file=False, config_file_initialize_app=False, hidden=False):
 
    """Register a kallithea-cli subcommand.
 

	
 
    If one of the config_file flags are true, a config file must be specified
 
    with -c and it is read and logging is configured. The configuration is
 
    available in the kallithea.CONFIG dict.
 

	
 
    If config_file_initialize_app is true, Kallithea, TurboGears global state
 
    (including tg.config), and database access will also be fully initialized.
 
    """
 
    cli_command = cli.command(hidden=hidden)
 
    if config_file or config_file_initialize_app:
 
        def annotator(annotated):
 
            @click.option('--config_file', '-c', help="Path to .ini file with app configuration.",
 
                type=click.Path(dir_okay=False, exists=True, readable=True), required=True)
 
            @functools.wraps(annotated) # reuse meta data from the wrapped function so click can see other options
 
            def runtime_wrapper(config_file, *args, **kwargs):
 
                path_to_ini_file = os.path.realpath(config_file)
 
                kallithea.CONFIG = paste.deploy.appconfig('config:' + path_to_ini_file)
 
                config_bytes = read_config(path_to_ini_file, strip_section_prefix=annotated.__name__)
 
                logging.config.fileConfig(cStringIO.StringIO(config_bytes))
 
                logging.config.fileConfig(cStringIO.StringIO(config_bytes),
 
                    {'__file__': path_to_ini_file, 'here': os.path.dirname(path_to_ini_file)})
 
                if config_file_initialize_app:
 
                    kallithea.config.middleware.make_app_without_logging(kallithea.CONFIG.global_conf, **kallithea.CONFIG.local_conf)
 
                    kallithea.lib.utils.setup_cache_regions(kallithea.CONFIG)
 
                return annotated(*args, **kwargs)
 
            return cli_command(runtime_wrapper)
 
        return annotator
 
    return cli_command
kallithea/bin/kallithea_cli_iis.py
Show inline comments
 
# -*- 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/>.
 
import os
 
import sys
 

	
 
import click
 

	
 
import kallithea
 
import kallithea.bin.kallithea_cli_base as cli_base
 

	
 

	
 
dispath_py_template = '''\
 
# Created by Kallithea 'kallithea-cli iis-install'
 
import sys
 

	
 
if hasattr(sys, "isapidllhandle"):
 
    import win32traceutil
 

	
 
import isapi_wsgi
 
import os
 

	
 
def __ExtensionFactory__():
 
    from paste.deploy import loadapp
 
    from logging.config import fileConfig
 
    fileConfig('%(inifile)s')
 
    fileConfig('%(inifile)s', {'__file__': '%(inifile)s', 'here': '%(inifiledir)s'})
 

	
 
    application = loadapp('config:%(inifile)s')
 

	
 
    def app(environ, start_response):
 
        user = environ.get('REMOTE_USER', None)
 
        if user is not None:
 
            os.environ['REMOTE_USER'] = user
 
        return application(environ, start_response)
 

	
 
    return isapi_wsgi.ISAPIThreadPoolHandler(app)
 

	
 
if __name__=='__main__':
 
    from isapi.install import *
 
    params = ISAPIParameters()
 
    sm = [ScriptMapParams(Extension="*", Flags=0)]
 
    vd = VirtualDirParameters(Name="%(virtualdir)s",
 
                              Description = "Kallithea",
 
                              ScriptMaps = sm,
 
                              ScriptMapUpdate = "replace")
 
    params.VirtualDirs = [vd]
 
    HandleCommandLine(params)
 
'''
 

	
 
@cli_base.register_command(config_file=True)
 
@click.option('--virtualdir', default='/',
 
        help='The virtual folder to install into on IIS.')
 
def iis_install(virtualdir):
 
    """Install into IIS using isapi-wsgi."""
 

	
 
    config_file_abs = kallithea.CONFIG['__file__']
 

	
 
    try:
 
        import isapi_wsgi
 
    except ImportError:
 
        sys.stderr.write('missing requirement: isapi-wsgi not installed\n')
 
        sys.exit(1)
 

	
 
    dispatchfile = os.path.join(os.getcwd(), 'dispatch.py')
 
    click.echo('Writing %s' % dispatchfile)
 
    with open(dispatchfile, 'w') as f:
 
        f.write(dispath_py_template % {
 
            'inifile': config_file_abs.replace('\\', '\\\\'),
 
            'inifiledir': os.path.dirname(config_file_abs).replace('\\', '\\\\'),
 
            'virtualdir': virtualdir,
 
            })
 

	
 
    click.echo('Run \'python "%s" install\' with administrative privileges '
 
        'to generate the _dispatch.dll file and install it into the '
 
        'default web site' % dispatchfile)
0 comments (0 inline, 0 general)