# HG changeset patch # User Thomas De Schampheleire # Date 1592423536 -7200 # Node ID a04d6926d694adc06e66a4555de3c79445793557 # Parent cc909683116c8733a2bdadd349027a53c582b2be# Parent 0bca9e828db247730518cbb4fd9225ea42592faf merge stable diff -r 0bca9e828db2 -r a04d6926d694 dev_requirements.txt --- a/dev_requirements.txt Thu Jun 11 20:50:26 2020 +0200 +++ b/dev_requirements.txt Wed Jun 17 21:52:16 2020 +0200 @@ -1,9 +1,9 @@ -pytest >= 4.6.6, < 5.4 +pytest >= 4.6.6, < 5.5 pytest-sugar >= 0.9.2, < 0.10 pytest-benchmark >= 3.2.2, < 3.3 pytest-localserver >= 0.5.0, < 0.6 mock >= 3.0.0, < 4.1 -Sphinx >= 1.8.0, < 2.4 +Sphinx >= 1.8.0, < 3.1 WebTest >= 2.0.6, < 2.1 isort == 4.3.21 -pyflakes == 2.1.1 +pyflakes == 2.2.0 diff -r 0bca9e828db2 -r a04d6926d694 development.ini --- a/development.ini Thu Jun 11 20:50:26 2020 +0200 +++ b/development.ini Wed Jun 17 21:52:16 2020 +0200 @@ -67,11 +67,11 @@ host = 0.0.0.0 port = 5000 -## WAITRESS ## +## Gearbox serve uses the Waitress web server ## use = egg:waitress#main -## number of worker threads +## avoid multi threading threads = 1 -## MAX BODY SIZE 100GB +## allow push of repos bigger than the default of 1 GB max_request_body_size = 107374182400 ## use poll instead of select, fixes fd limits, may not work on old ## windows systems. @@ -359,10 +359,10 @@ ## DB CONFIG ## ######################### -## SQLITE [default] sqlalchemy.url = sqlite:///%(here)s/kallithea.db?timeout=60 - -## see sqlalchemy docs for other backends +#sqlalchemy.url = postgresql://user:pass@localhost/kallithea +#sqlalchemy.url = mysql://user:pass@localhost/kallithea?charset=utf8 +## Note: the mysql:// prefix should also be used for MariaDB sqlalchemy.pool_recycle = 3600 diff -r 0bca9e828db2 -r a04d6926d694 docs/overview.rst diff -r 0bca9e828db2 -r a04d6926d694 kallithea/__init__.py --- a/kallithea/__init__.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/__init__.py Wed Jun 17 21:52:16 2020 +0200 @@ -34,7 +34,7 @@ if sys.version_info < (3, 6): raise Exception('Kallithea requires python 3.6 or later') -VERSION = (0, 6, 1) +VERSION = (0, 6, 99) BACKENDS = { 'hg': 'Mercurial repository', 'git': 'Git repository', diff -r 0bca9e828db2 -r a04d6926d694 kallithea/bin/kallithea_cli_base.py --- a/kallithea/bin/kallithea_cli_base.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/bin/kallithea_cli_base.py Wed Jun 17 21:52:16 2020 +0200 @@ -23,7 +23,7 @@ import paste.deploy import kallithea -import kallithea.config.middleware +import kallithea.config.application # kallithea_cli is usually invoked through the 'kallithea-cli' wrapper script @@ -77,7 +77,7 @@ logging.config.fileConfig(cp, {'__file__': path_to_ini_file, 'here': os.path.dirname(path_to_ini_file)}) if config_file_initialize_app: - kallithea.config.middleware.make_app(kallithea.CONFIG.global_conf, **kallithea.CONFIG.local_conf) + kallithea.config.application.make_app(kallithea.CONFIG.global_conf, **kallithea.CONFIG.local_conf) return annotated(*args, **kwargs) return cli_command(runtime_wrapper) return annotator diff -r 0bca9e828db2 -r a04d6926d694 kallithea/bin/kallithea_cli_db.py --- a/kallithea/bin/kallithea_cli_db.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/bin/kallithea_cli_db.py Wed Jun 17 21:52:16 2020 +0200 @@ -67,7 +67,7 @@ Session().commit() # initial repository scan - kallithea.config.middleware.make_app( + kallithea.config.application.make_app( kallithea.CONFIG.global_conf, **kallithea.CONFIG.local_conf) added, _ = kallithea.lib.utils.repo2db_mapper(kallithea.model.scm.ScmModel().repo_scan()) if added: diff -r 0bca9e828db2 -r a04d6926d694 kallithea/bin/kallithea_cli_ssh.py --- a/kallithea/bin/kallithea_cli_ssh.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/bin/kallithea_cli_ssh.py Wed Jun 17 21:52:16 2020 +0200 @@ -21,7 +21,7 @@ import kallithea import kallithea.bin.kallithea_cli_base as cli_base -from kallithea.lib.utils2 import str2bool +from kallithea.lib.utils2 import asbool from kallithea.lib.vcs.backends.git.ssh import GitSshHandler from kallithea.lib.vcs.backends.hg.ssh import MercurialSshHandler from kallithea.model.ssh_key import SshKeyModel, SshKeyModelException @@ -40,8 +40,7 @@ protocol access. The access will be granted as the specified user ID, and logged as using the specified key ID. """ - ssh_enabled = kallithea.CONFIG.get('ssh_enabled', False) - if not str2bool(ssh_enabled): + if not asbool(kallithea.CONFIG.get('ssh_enabled', False)): sys.stderr.write("SSH access is disabled.\n") return sys.exit(1) diff -r 0bca9e828db2 -r a04d6926d694 kallithea/config/app_cfg.py --- a/kallithea/config/app_cfg.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/config/app_cfg.py Wed Jun 17 21:52:16 2020 +0200 @@ -28,82 +28,57 @@ from alembic.migration import MigrationContext from alembic.script.base import ScriptDirectory from sqlalchemy import create_engine -from tg.configuration import AppConfig -from tg.support.converters import asbool +from tg import FullStackApplicationConfigurator import kallithea.lib.locale import kallithea.model.base import kallithea.model.meta from kallithea.lib import celerypylons -from kallithea.lib.middleware.https_fixup import HttpsFixup -from kallithea.lib.middleware.permanent_repo_url import PermanentRepoUrl -from kallithea.lib.middleware.simplegit import SimpleGit -from kallithea.lib.middleware.simplehg import SimpleHg -from kallithea.lib.middleware.wrapper import RequestWrapper from kallithea.lib.utils import check_git_version, load_rcextensions, set_app_settings, set_indexer_config, set_vcs_config -from kallithea.lib.utils2 import str2bool +from kallithea.lib.utils2 import asbool from kallithea.model import db log = logging.getLogger(__name__) -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. +base_config = FullStackApplicationConfigurator() - # 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. +base_config.update_blueprint({ + 'package': kallithea, - def __init__(self): - super(KallitheaAppConfig, self).__init__() - - self['package'] = kallithea + # Rendering Engines Configuration + 'renderers': [ + 'json', + 'mako', + ], + 'default_renderer': 'mako', + 'use_dotted_templatenames': False, - self['prefer_toscawidgets2'] = False - self['use_toscawidgets'] = False - - self['renderers'] = [] - - # Enable json in expose - self['renderers'].append('json') + # Configure Sessions, store data as JSON to avoid pickle security issues + 'session.enabled': True, + 'session.data_serializer': 'json', - # Configure template rendering - self['renderers'].append('mako') - self['default_renderer'] = 'mako' - self['use_dotted_templatenames'] = False + # Configure the base SQLALchemy Setup + 'use_sqlalchemy': True, + 'model': kallithea.model.base, + 'DBSession': kallithea.model.meta.Session, - # 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. + 'auth_backend': None, - # Configure App without an authentication backend. - self['auth_backend'] = None - - # 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] + # 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. + 'errorpage.status_codes': [400, 401, 403, 404], - # Disable transaction manager -- currently Kallithea takes care of transactions itself - self['tm.enabled'] = False + # Disable transaction manager -- currently Kallithea takes care of transactions itself + 'tm.enabled': False, - # Set the default i18n source language so TG doesn't search beyond 'en' in Accept-Language. - self['i18n.lang'] = 'en' - - -base_config = KallitheaAppConfig() + # Set the default i18n source language so TG doesn't search beyond 'en' in Accept-Language. + 'i18n.lang': 'en', +}) # DebugBar, a debug toolbar for TurboGears2. # (https://github.com/TurboGears/tgext.debugbar) @@ -160,7 +135,7 @@ # store some globals into kallithea kallithea.DEFAULT_USER_ID = db.User.get_default_user().user_id - if str2bool(config.get('use_celery')): + if asbool(config.get('use_celery')): kallithea.CELERY_APP = celerypylons.make_app() kallithea.CONFIG = config @@ -188,27 +163,3 @@ tg.hooks.register('configure_new_app', setup_configuration) - - -def setup_application(app): - config = app.config - - # 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) - - # 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) - - app = PermanentRepoUrl(app, config) - - # 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) - - return app - - -tg.hooks.register('before_config', setup_application) diff -r 0bca9e828db2 -r a04d6926d694 kallithea/config/application.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kallithea/config/application.py Wed Jun 17 21:52:16 2020 +0200 @@ -0,0 +1,68 @@ +# -*- 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 . +"""WSGI middleware initialization for the Kallithea application.""" + +from kallithea.config.app_cfg import base_config +from kallithea.lib.middleware.https_fixup import HttpsFixup +from kallithea.lib.middleware.permanent_repo_url import PermanentRepoUrl +from kallithea.lib.middleware.simplegit import SimpleGit +from kallithea.lib.middleware.simplehg import SimpleHg +from kallithea.lib.middleware.wrapper import RequestWrapper +from kallithea.lib.utils2 import asbool + + +__all__ = ['make_app'] + + +def wrap_app(app): + """Wrap the TG WSGI application in Kallithea middleware""" + config = app.config + + # 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) + + # 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) + + app = PermanentRepoUrl(app, config) + + # Optional and undocumented wrapper - gives more verbose request/response logging, but has a slight overhead + if asbool(config.get('use_wsgi_wrapper')): + app = RequestWrapper(app, config) + + return app + + +def make_app(global_conf, **app_conf): + """ + Set up Kallithea with the settings found in the PasteDeploy configuration + file used. + + :param global_conf: The global settings for Kallithea (those + defined under the ``[DEFAULT]`` section). + :return: The Kallithea application with all the relevant middleware + loaded. + + This is the PasteDeploy factory for the Kallithea application. + + ``app_conf`` contains all the application-specific settings (those defined + under ``[app:main]``. + """ + assert app_conf.get('sqlalchemy.url') # must be called with a Kallithea .ini file, which for example must have this config option + assert global_conf.get('here') and global_conf.get('__file__') # app config should be initialized the paste way ... + + return base_config.make_wsgi_app(global_conf, app_conf, wrap_app=wrap_app) diff -r 0bca9e828db2 -r a04d6926d694 kallithea/config/environment.py --- a/kallithea/config/environment.py Thu Jun 11 20:50:26 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -# -*- 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 . -"""WSGI environment setup for Kallithea.""" - -from kallithea.config.app_cfg import base_config - - -__all__ = ['load_environment'] - -# Use base_config to setup the environment loader function -load_environment = base_config.make_load_environment() diff -r 0bca9e828db2 -r a04d6926d694 kallithea/config/middleware.py --- a/kallithea/config/middleware.py Thu Jun 11 20:50:26 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -# -*- 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 . -"""WSGI middleware initialization for the Kallithea application.""" - -from kallithea.config.app_cfg import base_config -from kallithea.config.environment import load_environment - - -__all__ = ['make_app'] - -# Use base_config to setup the necessary PasteDeploy application factory. -# make_base_app will wrap the TurboGears2 app with all the middleware it needs. -make_base_app = base_config.setup_tg_wsgi_app(load_environment) - - -def make_app(global_conf, full_stack=True, **app_conf): - """ - Set up Kallithea with the settings found in the PasteDeploy configuration - file used. - - :param global_conf: The global settings for Kallithea (those - defined under the ``[DEFAULT]`` section). - :type global_conf: dict - :param full_stack: Should the whole TurboGears2 stack be set up? - :type full_stack: str or bool - :return: The Kallithea application with all the relevant middleware - loaded. - - This is the PasteDeploy factory for the Kallithea application. - - ``app_conf`` contains all the application-specific settings (those defined - under ``[app:main]``. - """ - assert app_conf.get('sqlalchemy.url') # must be called with a Kallithea .ini file, which for example must have this config option - assert global_conf.get('here') and global_conf.get('__file__') # app config should be initialized the paste way ... - return make_base_app(global_conf, full_stack=full_stack, **app_conf) diff -r 0bca9e828db2 -r a04d6926d694 kallithea/controllers/admin/permissions.py --- a/kallithea/controllers/admin/permissions.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/controllers/admin/permissions.py Wed Jun 17 21:52:16 2020 +0200 @@ -61,18 +61,22 @@ super(PermissionsController, self)._before(*args, **kwargs) def __load_data(self): + # Permissions for the Default user on new repositories c.repo_perms_choices = [('repository.none', _('None'),), ('repository.read', _('Read'),), ('repository.write', _('Write'),), ('repository.admin', _('Admin'),)] + # Permissions for the Default user on new repository groups c.group_perms_choices = [('group.none', _('None'),), ('group.read', _('Read'),), ('group.write', _('Write'),), ('group.admin', _('Admin'),)] + # Permissions for the Default user on new user groups c.user_group_perms_choices = [('usergroup.none', _('None'),), ('usergroup.read', _('Read'),), ('usergroup.write', _('Write'),), ('usergroup.admin', _('Admin'),)] + # Registration - allow new Users to create an account c.register_choices = [ ('hg.register.none', _('Disabled')), @@ -80,26 +84,18 @@ _('Allowed with manual account activation')), ('hg.register.auto_activate', _('Allowed with automatic account activation')), ] - + # External auth account activation c.extern_activate_choices = [ ('hg.extern_activate.manual', _('Manual activation of external account')), ('hg.extern_activate.auto', _('Automatic activation of external account')), ] - + # Top level repository creation c.repo_create_choices = [('hg.create.none', _('Disabled')), ('hg.create.repository', _('Enabled'))] - - c.repo_create_on_write_choices = [ - ('hg.create.write_on_repogroup.true', _('Enabled')), - ('hg.create.write_on_repogroup.false', _('Disabled')), - ] - + # User group creation c.user_group_create_choices = [('hg.usergroup.create.false', _('Disabled')), ('hg.usergroup.create.true', _('Enabled'))] - - c.repo_group_create_choices = [('hg.repogroup.create.false', _('Disabled')), - ('hg.repogroup.create.true', _('Enabled'))] - + # Repository forking: c.fork_choices = [('hg.fork.none', _('Disabled')), ('hg.fork.repository', _('Enabled'))] @@ -112,7 +108,6 @@ [x[0] for x in c.group_perms_choices], [x[0] for x in c.user_group_perms_choices], [x[0] for x in c.repo_create_choices], - [x[0] for x in c.repo_create_on_write_choices], [x[0] for x in c.repo_group_create_choices], [x[0] for x in c.user_group_create_choices], [x[0] for x in c.fork_choices], @@ -157,15 +152,9 @@ if p.permission.permission_name.startswith('usergroup.'): defaults['default_user_group_perm'] = p.permission.permission_name - if p.permission.permission_name.startswith('hg.create.write_on_repogroup.'): - defaults['create_on_write'] = p.permission.permission_name - elif p.permission.permission_name.startswith('hg.create.'): defaults['default_repo_create'] = p.permission.permission_name - if p.permission.permission_name.startswith('hg.repogroup.'): - defaults['default_repo_group_create'] = p.permission.permission_name - if p.permission.permission_name.startswith('hg.usergroup.'): defaults['default_user_group_create'] = p.permission.permission_name diff -r 0bca9e828db2 -r a04d6926d694 kallithea/controllers/admin/repo_groups.py --- a/kallithea/controllers/admin/repo_groups.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/controllers/admin/repo_groups.py Wed Jun 17 21:52:16 2020 +0200 @@ -63,7 +63,7 @@ exclude is used for not moving group to itself TODO: also exclude descendants Note: only admin can create top level groups """ - repo_groups = AvailableRepoGroupChoices([], 'admin', extras) + repo_groups = AvailableRepoGroupChoices('admin', extras) exclude_group_ids = set(rg.group_id for rg in exclude) c.repo_groups = [rg for rg in repo_groups if rg[0] not in exclude_group_ids] diff -r 0bca9e828db2 -r a04d6926d694 kallithea/controllers/admin/repos.py --- a/kallithea/controllers/admin/repos.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/controllers/admin/repos.py Wed Jun 17 21:52:16 2020 +0200 @@ -39,7 +39,7 @@ import kallithea from kallithea.config.routing import url from kallithea.lib import helpers as h -from kallithea.lib.auth import HasPermissionAny, HasRepoPermissionLevelDecorator, LoginRequired, NotAnonymous +from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired, NotAnonymous from kallithea.lib.base import BaseRepoController, jsonify, render from kallithea.lib.exceptions import AttachedForksError from kallithea.lib.utils import action_logger @@ -76,14 +76,9 @@ return repo_obj def __load_defaults(self, repo=None): - top_perms = ['hg.create.repository'] - if HasPermissionAny('hg.create.write_on_repogroup.true')(): - repo_group_perm_level = 'write' - else: - repo_group_perm_level = 'admin' extras = [] if repo is None else [repo.group] - c.repo_groups = AvailableRepoGroupChoices(top_perms, repo_group_perm_level, extras) + c.repo_groups = AvailableRepoGroupChoices('write', extras) c.landing_revs_choices, c.landing_revs = ScmModel().get_repo_landing_revs(repo) diff -r 0bca9e828db2 -r a04d6926d694 kallithea/controllers/feed.py --- a/kallithea/controllers/feed.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/controllers/feed.py Wed Jun 17 21:52:16 2020 +0200 @@ -39,7 +39,7 @@ from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired from kallithea.lib.base import BaseRepoController from kallithea.lib.diffs import DiffProcessor -from kallithea.lib.utils2 import safe_int, safe_str, str2bool +from kallithea.lib.utils2 import asbool, safe_int, safe_str log = logging.getLogger(__name__) @@ -92,7 +92,7 @@ desc_msg.append(h.urlify_text(cs.message)) desc_msg.append('\n') desc_msg.extend(changes) - if str2bool(CONFIG.get('rss_include_diff', False)): + if asbool(CONFIG.get('rss_include_diff', False)): desc_msg.append('\n\n') desc_msg.append(safe_str(raw_diff)) desc_msg.append('') diff -r 0bca9e828db2 -r a04d6926d694 kallithea/controllers/files.py --- a/kallithea/controllers/files.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/controllers/files.py Wed Jun 17 21:52:16 2020 +0200 @@ -46,7 +46,7 @@ from kallithea.lib.base import BaseRepoController, jsonify, render from kallithea.lib.exceptions import NonRelativePathError from kallithea.lib.utils import action_logger -from kallithea.lib.utils2 import convert_line_endings, detect_mode, safe_int, safe_str, str2bool +from kallithea.lib.utils2 import asbool, convert_line_endings, detect_mode, safe_int, safe_str from kallithea.lib.vcs.backends.base import EmptyChangeset from kallithea.lib.vcs.conf import settings from kallithea.lib.vcs.exceptions import (ChangesetDoesNotExistError, ChangesetError, EmptyRepositoryError, ImproperArchiveTypeError, NodeAlreadyExistsError, @@ -577,7 +577,7 @@ # to reduce JS and callbacks if request.GET.get('show_rev'): - if str2bool(request.GET.get('annotate', 'False')): + if asbool(request.GET.get('annotate', 'False')): _url = url('files_annotate_home', repo_name=c.repo_name, revision=diff1, f_path=c.f_path) else: diff -r 0bca9e828db2 -r a04d6926d694 kallithea/controllers/forks.py --- a/kallithea/controllers/forks.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/controllers/forks.py Wed Jun 17 21:52:16 2020 +0200 @@ -38,7 +38,7 @@ import kallithea import kallithea.lib.helpers as h from kallithea.config.routing import url -from kallithea.lib.auth import HasPermissionAny, HasPermissionAnyDecorator, HasRepoPermissionLevel, HasRepoPermissionLevelDecorator, LoginRequired +from kallithea.lib.auth import HasPermissionAnyDecorator, HasRepoPermissionLevel, HasRepoPermissionLevelDecorator, LoginRequired from kallithea.lib.base import BaseRepoController, render from kallithea.lib.page import Page from kallithea.lib.utils2 import safe_int @@ -54,11 +54,7 @@ class ForksController(BaseRepoController): def __load_defaults(self): - if HasPermissionAny('hg.create.write_on_repogroup.true')(): - repo_group_perm_level = 'write' - else: - repo_group_perm_level = 'admin' - c.repo_groups = AvailableRepoGroupChoices(['hg.create.repository'], repo_group_perm_level) + c.repo_groups = AvailableRepoGroupChoices('write') c.landing_revs_choices, c.landing_revs = ScmModel().get_repo_landing_revs() diff -r 0bca9e828db2 -r a04d6926d694 kallithea/lib/auth.py --- a/kallithea/lib/auth.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/lib/auth.py Wed Jun 17 21:52:16 2020 +0200 @@ -149,7 +149,6 @@ # based on default permissions, just set everything to admin #================================================================== permissions[GLOBAL].add('hg.admin') - permissions[GLOBAL].add('hg.create.write_on_repogroup.true') # repositories for perm in default_repo_perms: @@ -242,7 +241,7 @@ # for each kind of global permissions, only keep the one with heighest weight kind_max_perm = {} - for perm in sorted(permissions[GLOBAL], key=lambda n: PERM_WEIGHTS[n]): + for perm in sorted(permissions[GLOBAL], key=lambda n: PERM_WEIGHTS.get(n, -1)): kind = perm.rsplit('.', 1)[0] kind_max_perm[kind] = perm permissions[GLOBAL] = set(kind_max_perm.values()) diff -r 0bca9e828db2 -r a04d6926d694 kallithea/lib/auth_modules/__init__.py --- a/kallithea/lib/auth_modules/__init__.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/lib/auth_modules/__init__.py Wed Jun 17 21:52:16 2020 +0200 @@ -21,7 +21,7 @@ from kallithea.lib.auth import AuthUser, PasswordGenerator from kallithea.lib.compat import hybrid_property -from kallithea.lib.utils2 import str2bool +from kallithea.lib.utils2 import asbool from kallithea.model.db import Setting, User from kallithea.model.meta import Session from kallithea.model.user import UserModel @@ -350,7 +350,7 @@ plugin_settings[v["name"]] = setting.app_settings_value if setting else None log.debug('Settings for auth plugin %s: %s', plugin_name, plugin_settings) - if not str2bool(plugin_settings["enabled"]): + if not asbool(plugin_settings["enabled"]): log.info("Authentication plugin %s is disabled, skipping for %s", module, username) continue diff -r 0bca9e828db2 -r a04d6926d694 kallithea/lib/auth_modules/auth_container.py --- a/kallithea/lib/auth_modules/auth_container.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/lib/auth_modules/auth_container.py Wed Jun 17 21:52:16 2020 +0200 @@ -29,7 +29,7 @@ from kallithea.lib import auth_modules from kallithea.lib.compat import hybrid_property -from kallithea.lib.utils2 import str2bool +from kallithea.lib.utils2 import asbool from kallithea.model.db import Setting @@ -131,7 +131,7 @@ username = environ.get(header) log.debug('extracted %s:%s', header, username) - if username and str2bool(settings.get('clean_username')): + if username and asbool(settings.get('clean_username')): log.debug('Received username %s from container', username) username = self._clean_username(username) log.debug('New cleanup user is: %s', username) diff -r 0bca9e828db2 -r a04d6926d694 kallithea/lib/base.py --- a/kallithea/lib/base.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/lib/base.py Wed Jun 17 21:52:16 2020 +0200 @@ -49,7 +49,7 @@ from kallithea.lib.auth import AuthUser, HasPermissionAnyMiddleware from kallithea.lib.exceptions import UserCreationError from kallithea.lib.utils import get_repo_slug, is_valid_repo -from kallithea.lib.utils2 import AttributeDict, ascii_bytes, safe_int, safe_str, set_hook_environment, str2bool +from kallithea.lib.utils2 import AttributeDict, asbool, ascii_bytes, safe_int, safe_str, set_hook_environment from kallithea.lib.vcs.exceptions import ChangesetDoesNotExistError, EmptyRepositoryError, RepositoryError from kallithea.model import meta from kallithea.model.db import PullRequest, Repository, Setting, User @@ -375,14 +375,14 @@ c.visual = AttributeDict({}) ## DB stored - c.visual.show_public_icon = str2bool(rc_config.get('show_public_icon')) - c.visual.show_private_icon = str2bool(rc_config.get('show_private_icon')) - c.visual.stylify_metalabels = str2bool(rc_config.get('stylify_metalabels')) + c.visual.show_public_icon = asbool(rc_config.get('show_public_icon')) + c.visual.show_private_icon = asbool(rc_config.get('show_private_icon')) + c.visual.stylify_metalabels = asbool(rc_config.get('stylify_metalabels')) c.visual.page_size = safe_int(rc_config.get('dashboard_items', 100)) c.visual.admin_grid_items = safe_int(rc_config.get('admin_grid_items', 100)) - c.visual.repository_fields = str2bool(rc_config.get('repository_fields')) - c.visual.show_version = str2bool(rc_config.get('show_version')) - c.visual.use_gravatar = str2bool(rc_config.get('use_gravatar')) + c.visual.repository_fields = asbool(rc_config.get('repository_fields')) + c.visual.show_version = asbool(rc_config.get('show_version')) + c.visual.use_gravatar = asbool(rc_config.get('use_gravatar')) c.visual.gravatar_url = rc_config.get('gravatar_url') c.ga_code = rc_config.get('ga_code') @@ -404,9 +404,9 @@ c.clone_ssh_tmpl = rc_config.get('clone_ssh_tmpl') or Repository.DEFAULT_CLONE_SSH ## INI stored - c.visual.allow_repo_location_change = str2bool(config.get('allow_repo_location_change', True)) - c.visual.allow_custom_hooks_settings = str2bool(config.get('allow_custom_hooks_settings', True)) - c.ssh_enabled = str2bool(config.get('ssh_enabled', False)) + c.visual.allow_repo_location_change = asbool(config.get('allow_repo_location_change', True)) + c.visual.allow_custom_hooks_settings = asbool(config.get('allow_custom_hooks_settings', True)) + c.ssh_enabled = asbool(config.get('ssh_enabled', False)) c.instance_id = config.get('instance_id') c.issues_url = config.get('bugtracker', url('issues_url')) diff -r 0bca9e828db2 -r a04d6926d694 kallithea/lib/celerylib/tasks.py --- a/kallithea/lib/celerylib/tasks.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/lib/celerylib/tasks.py Wed Jun 17 21:52:16 2020 +0200 @@ -42,7 +42,7 @@ from kallithea.lib.hooks import log_create_repository from kallithea.lib.rcmail.smtp_mailer import SmtpMailer from kallithea.lib.utils import action_logger -from kallithea.lib.utils2 import ascii_bytes, str2bool +from kallithea.lib.utils2 import asbool, ascii_bytes from kallithea.lib.vcs.utils import author_email from kallithea.model.db import RepoGroup, Repository, Statistics, User @@ -289,9 +289,9 @@ passwd = email_config.get('smtp_password') mail_server = email_config.get('smtp_server') mail_port = email_config.get('smtp_port') - tls = str2bool(email_config.get('smtp_use_tls')) - ssl = str2bool(email_config.get('smtp_use_ssl')) - debug = str2bool(email_config.get('debug')) + tls = asbool(email_config.get('smtp_use_tls')) + ssl = asbool(email_config.get('smtp_use_ssl')) + debug = asbool(email_config.get('debug')) smtp_auth = email_config.get('smtp_auth') logmsg = ("Mail details:\n" diff -r 0bca9e828db2 -r a04d6926d694 kallithea/lib/colored_formatter.py --- a/kallithea/lib/colored_formatter.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/lib/colored_formatter.py Wed Jun 17 21:52:16 2020 +0200 @@ -13,6 +13,7 @@ # along with this program. If not, see . import logging +import sys BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(30, 38) @@ -65,15 +66,18 @@ def __init__(self, *args, **kwargs): # can't do super(...) here because Formatter is an old school class logging.Formatter.__init__(self, *args, **kwargs) + self.plain = not getattr(sys.stderr, 'isatty', lambda: False)() def format(self, record): """ Changes record's levelname to use with COLORS enum """ + def_record = logging.Formatter.format(self, record) + if self.plain: + return def_record levelname = record.levelname start = COLOR_SEQ % (COLORS[levelname]) - def_record = logging.Formatter.format(self, record) end = RESET_SEQ colored_record = ''.join([start, def_record, end]) @@ -85,14 +89,17 @@ def __init__(self, *args, **kwargs): # can't do super(...) here because Formatter is an old school class logging.Formatter.__init__(self, *args, **kwargs) + self.plain = not getattr(sys.stderr, 'isatty', lambda: False)() def format(self, record): """ Changes record's levelname to use with COLORS enum """ + def_record = format_sql(logging.Formatter.format(self, record)) + if self.plain: + return def_record start = COLOR_SEQ % (COLORS['SQL']) - def_record = format_sql(logging.Formatter.format(self, record)) end = RESET_SEQ colored_record = ''.join([start, def_record, end]) diff -r 0bca9e828db2 -r a04d6926d694 kallithea/lib/db_manage.py --- a/kallithea/lib/db_manage.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/lib/db_manage.py Wed Jun 17 21:52:16 2020 +0200 @@ -37,11 +37,9 @@ from sqlalchemy.engine import create_engine from kallithea.model.base import init_model -from kallithea.model.db import Permission, RepoGroup, Repository, Setting, Ui, User, UserRepoGroupToPerm, UserToPerm -#from kallithea.model import meta +from kallithea.model.db import Repository, Setting, Ui, User from kallithea.model.meta import Base, Session from kallithea.model.permission import PermissionModel -from kallithea.model.repo_group import RepoGroupModel from kallithea.model.user import UserModel @@ -128,42 +126,6 @@ log.info('Created tables for %s', self.dbname) - def fix_repo_paths(self): - """ - Fixes a old kallithea version path into new one without a '*' - """ - - paths = Ui.query() \ - .filter(Ui.ui_key == '/') \ - .scalar() - - paths.ui_value = paths.ui_value.replace('*', '') - - self.sa.commit() - - def fix_default_user(self): - """ - Fixes a old default user with some 'nicer' default values, - used mostly for anonymous access - """ - def_user = User.query().filter_by(is_default_user=True).one() - - def_user.name = 'Anonymous' - def_user.lastname = 'User' - def_user.email = 'anonymous@kallithea-scm.org' - - self.sa.commit() - - def fix_settings(self): - """ - Fixes kallithea settings adds ga_code key for google analytics - """ - - hgsettings3 = Setting('ga_code', '') - - self.sa.add(hgsettings3) - self.sa.commit() - def admin_prompt(self, second=False): if not self.tests: import getpass @@ -244,45 +206,6 @@ setting = Setting(k, v, t) self.sa.add(setting) - def fixup_groups(self): - def_usr = User.get_default_user() - for g in RepoGroup.query().all(): - g.group_name = g.get_new_name(g.name) - # get default perm - default = UserRepoGroupToPerm.query() \ - .filter(UserRepoGroupToPerm.group == g) \ - .filter(UserRepoGroupToPerm.user == def_usr) \ - .scalar() - - if default is None: - log.debug('missing default permission for group %s adding', g) - RepoGroupModel()._create_default_perms(g) - - def reset_permissions(self, username): - """ - Resets permissions to default state, useful when old systems had - bad permissions, we must clean them up - - :param username: - """ - default_user = User.get_by_username(username) - if not default_user: - return - - u2p = UserToPerm.query() \ - .filter(UserToPerm.user == default_user).all() - fixed = False - if len(u2p) != len(Permission.DEFAULT_USER_PERMISSIONS): - for p in u2p: - Session().delete(p) - fixed = True - self.populate_default_permissions() - return fixed - - def update_repo_info(self): - for repo in Repository.query(): - repo.update_changeset_cache() - def prompt_repo_root_path(self, test_repo_path='', retries=3): _path = self.cli_args.get('repos_location') if retries == 3: diff -r 0bca9e828db2 -r a04d6926d694 kallithea/lib/diffs.py --- a/kallithea/lib/diffs.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/lib/diffs.py Wed Jun 17 21:52:16 2020 +0200 @@ -89,10 +89,10 @@ 'table_class': table_class }) - for diff in parsed_lines: - for line in diff['chunks']: + for file_info in parsed_lines: + for chunk in file_info['chunks']: _html_empty = False - for change in line: + for change in chunk: _html.append('''\n''' % { 'lc': line_class, 'action': change['action'] @@ -100,19 +100,16 @@ anchor_old_id = '' anchor_new_id = '' anchor_old = "%(filename)s_o%(oldline_no)s" % { - 'filename': _safe_id(diff['filename']), + 'filename': _safe_id(file_info['filename']), 'oldline_no': change['old_lineno'] } - anchor_new = "%(filename)s_n%(oldline_no)s" % { - 'filename': _safe_id(diff['filename']), - 'oldline_no': change['new_lineno'] + anchor_new = "%(filename)s_n%(newline_no)s" % { + 'filename': _safe_id(file_info['filename']), + 'newline_no': change['new_lineno'] } - cond_old = (change['old_lineno'] != '...' and - change['old_lineno']) - cond_new = (change['new_lineno'] != '...' and - change['new_lineno']) - no_lineno = (change['old_lineno'] == '...' and - change['new_lineno'] == '...') + cond_old = change['old_lineno'] + cond_new = change['new_lineno'] + no_lineno = not change['old_lineno'] and not change['new_lineno'] if cond_old: anchor_old_id = 'id="%s"' % anchor_old if cond_new: @@ -453,7 +450,7 @@ return self.adds, self.removes -_escape_re = re.compile(r'(&)|(<)|(>)|(\t)|(\r)|(?<=.)( \n| $)') +_escape_re = re.compile(r'(&)|(<)|(>)|(\t)|(\r)|(?<=.)( \n| $)|(\t\n|\t$)') def _escaper(string): @@ -470,11 +467,13 @@ if groups[2]: return '>' if groups[3]: - return '\t' + return '\t' # Note: trailing tabs will get a longer match later if groups[4]: return '' if groups[5]: return ' ' + if groups[6]: + return '\t' assert False return _escape_re.sub(substitute, safe_str(string)) @@ -585,8 +584,8 @@ # skip context only if it's first line if int(gr[0]) > 1: lines.append({ - 'old_lineno': '...', - 'new_lineno': '...', + 'old_lineno': '', + 'new_lineno': '', 'action': 'context', 'line': line, }) @@ -630,8 +629,8 @@ # we need to append to lines, since this is not # counted in the line specs of diff lines.append({ - 'old_lineno': '...', - 'new_lineno': '...', + 'old_lineno': '', + 'new_lineno': '', 'action': 'context', 'line': line, }) diff -r 0bca9e828db2 -r a04d6926d694 kallithea/lib/helpers.py --- a/kallithea/lib/helpers.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/lib/helpers.py Wed Jun 17 21:52:16 2020 +0200 @@ -48,7 +48,7 @@ from kallithea.lib.pygmentsutils import get_custom_lexer from kallithea.lib.utils2 import MENTIONS_REGEX, AttributeDict from kallithea.lib.utils2 import age as _age -from kallithea.lib.utils2 import credentials_filter, safe_bytes, safe_int, safe_str, str2bool, time_to_datetime +from kallithea.lib.utils2 import asbool, credentials_filter, safe_bytes, safe_int, safe_str, time_to_datetime from kallithea.lib.vcs.backends.base import BaseChangeset, EmptyChangeset from kallithea.lib.vcs.exceptions import ChangesetDoesNotExistError #============================================================================== @@ -526,7 +526,7 @@ """ from kallithea import CONFIG def_len = safe_int(CONFIG.get('show_sha_length', 12)) - show_rev = str2bool(CONFIG.get('show_revision_number', False)) + show_rev = asbool(CONFIG.get('show_revision_number', False)) raw_id = cs.raw_id[:def_len] if show_rev: @@ -932,7 +932,7 @@ else: # if src is empty then there was no gravatar, so we use a font icon html = ("""""" - .format(cls=cls, size=size, src=src)) + .format(cls=cls, size=size)) return literal(html) diff -r 0bca9e828db2 -r a04d6926d694 kallithea/lib/hooks.py --- a/kallithea/lib/hooks.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/lib/hooks.py Wed Jun 17 21:52:16 2020 +0200 @@ -307,14 +307,14 @@ connect to the database. """ import paste.deploy - import kallithea.config.middleware + import kallithea.config.application extras = get_hook_environment() path_to_ini_file = extras['config'] kallithea.CONFIG = paste.deploy.appconfig('config:' + path_to_ini_file) #logging.config.fileConfig(ini_file_path) # Note: we are in a different process - don't use configured logging - kallithea.config.middleware.make_app(kallithea.CONFIG.global_conf, **kallithea.CONFIG.local_conf) + kallithea.config.application.make_app(kallithea.CONFIG.global_conf, **kallithea.CONFIG.local_conf) # fix if it's not a bare repo if repo_path.endswith(os.sep + '.git'): diff -r 0bca9e828db2 -r a04d6926d694 kallithea/lib/inifile.py --- a/kallithea/lib/inifile.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/lib/inifile.py Wed Jun 17 21:52:16 2020 +0200 @@ -119,9 +119,6 @@ #variable7 = 7.1 #variable8 = 8.0 - variable8 = None - variable9 = None - [fourth-section] fourth = "four" fourth_extra = 4 @@ -180,7 +177,7 @@ new_value = section_settings[key] if new_value == line_value: line = line.lstrip('#') - else: + elif new_value is not None: line += '\n%s = %s' % (key, new_value) section_settings.pop(key) return line @@ -189,8 +186,12 @@ # 3rd pass: # settings that haven't been consumed yet at is appended to section - if section_settings: - lines += '\n' + ''.join('%s = %s\n' % (key, value) for key, value in sorted(section_settings.items())) + append_lines = ''.join( + '%s = %s\n' % (key, value) + for key, value in sorted(section_settings.items()) + if value is not None) + if append_lines: + lines += '\n' + append_lines return sectionname + '\n' + re.sub('[ \t]+\n', '\n', lines) diff -r 0bca9e828db2 -r a04d6926d694 kallithea/lib/middleware/https_fixup.py --- a/kallithea/lib/middleware/https_fixup.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/lib/middleware/https_fixup.py Wed Jun 17 21:52:16 2020 +0200 @@ -26,7 +26,7 @@ """ -from kallithea.lib.utils2 import str2bool +from kallithea.lib.utils2 import asbool class HttpsFixup(object): @@ -37,11 +37,11 @@ def __call__(self, environ, start_response): self.__fixup(environ) - debug = str2bool(self.config.get('debug')) + debug = asbool(self.config.get('debug')) is_ssl = environ['wsgi.url_scheme'] == 'https' def custom_start_response(status, headers, exc_info=None): - if is_ssl and str2bool(self.config.get('use_htsts')) and not debug: + if is_ssl and asbool(self.config.get('use_htsts')) and not debug: headers.append(('Strict-Transport-Security', 'max-age=8640000; includeSubDomains')) return start_response(status, headers, exc_info) @@ -66,7 +66,7 @@ org_proto = proto # if we have force, just override - if str2bool(self.config.get('force_https')): + if asbool(self.config.get('force_https')): proto = 'https' environ['wsgi.url_scheme'] = proto diff -r 0bca9e828db2 -r a04d6926d694 kallithea/lib/paster_commands/template.ini.mako --- a/kallithea/lib/paster_commands/template.ini.mako Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/lib/paster_commands/template.ini.mako Wed Jun 17 21:52:16 2020 +0200 @@ -69,7 +69,7 @@ port = ${port} %if http_server == 'gearbox': -<%text>## Gearbox default web server ## +<%text>## Gearbox serve uses the built-in development web server ## use = egg:gearbox#wsgiref <%text>## nr of worker threads to spawn threadpool_workers = 1 @@ -79,22 +79,22 @@ use_threadpool = true %elif http_server == 'gevent': -<%text>## Gearbox gevent web server ## +<%text>## Gearbox serve uses the gevent web server ## use = egg:gearbox#gevent %elif http_server == 'waitress': -<%text>## WAITRESS ## +<%text>## Gearbox serve uses the Waitress web server ## use = egg:waitress#main -<%text>## number of worker threads +<%text>## avoid multi threading threads = 1 -<%text>## MAX BODY SIZE 100GB +<%text>## allow push of repos bigger than the default of 1 GB max_request_body_size = 107374182400 <%text>## use poll instead of select, fixes fd limits, may not work on old <%text>## windows systems. #asyncore_use_poll = True %elif http_server == 'gunicorn': -<%text>## GUNICORN ## +<%text>## Gearbox serve uses the Gunicorn web server ## use = egg:gunicorn#main <%text>## number of process workers. You must set `instance_id = *` when this option <%text>## is set to more than one worker @@ -453,21 +453,22 @@ <%text>######################### %if database_engine == 'sqlite': -<%text>## SQLITE [default] sqlalchemy.url = sqlite:///%(here)s/kallithea.db?timeout=60 - -%elif database_engine == 'postgres': -<%text>## POSTGRESQL +%else: +#sqlalchemy.url = sqlite:///%(here)s/kallithea.db?timeout=60 +%endif +%if database_engine == 'postgres': sqlalchemy.url = postgresql://user:pass@localhost/kallithea - -%elif database_engine == 'mysql': -<%text>## MySQL +%else: +#sqlalchemy.url = postgresql://user:pass@localhost/kallithea +%endif +%if database_engine == 'mysql': sqlalchemy.url = mysql://user:pass@localhost/kallithea?charset=utf8 +%else: +#sqlalchemy.url = mysql://user:pass@localhost/kallithea?charset=utf8 +%endif <%text>## Note: the mysql:// prefix should also be used for MariaDB -%endif -<%text>## see sqlalchemy docs for other backends - sqlalchemy.pool_recycle = 3600 <%text>################################ diff -r 0bca9e828db2 -r a04d6926d694 kallithea/lib/utils2.py --- a/kallithea/lib/utils2.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/lib/utils2.py Wed Jun 17 21:52:16 2020 +0200 @@ -38,6 +38,7 @@ import urlobject from tg.i18n import ugettext as _ from tg.i18n import ungettext +from tg.support.converters import asbool, aslist from webhelpers2.text import collapse, remove_formatting, strip_tags from kallithea.lib.vcs.utils import ascii_bytes, ascii_str, safe_bytes, safe_str # re-export @@ -51,6 +52,8 @@ # mute pyflakes "imported but unused" +assert asbool +assert aslist assert ascii_bytes assert ascii_str assert safe_bytes @@ -58,44 +61,6 @@ assert LazyProperty -def str2bool(_str): - """ - returns True/False value from given string, it tries to translate the - string into boolean - - :param _str: string value to translate into boolean - :rtype: boolean - :returns: boolean from given string - """ - if _str is None: - return False - if _str in (True, False): - return _str - _str = str(_str).strip().lower() - return _str in ('t', 'true', 'y', 'yes', 'on', '1') - - -def aslist(obj, sep=None, strip=True): - """ - Returns given string separated by sep as list - - :param obj: - :param sep: - :param strip: - """ - if isinstance(obj, (str)): - lst = obj.split(sep) - if strip: - lst = [v.strip() for v in lst] - return lst - elif isinstance(obj, (list, tuple)): - return obj - elif obj is None: - return [] - else: - return [obj] - - def convert_line_endings(line, mode): """ Converts a given line "line end" according to given mode diff -r 0bca9e828db2 -r a04d6926d694 kallithea/lib/vcs/backends/hg/repository.py --- a/kallithea/lib/vcs/backends/hg/repository.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/lib/vcs/backends/hg/repository.py Wed Jun 17 21:52:16 2020 +0200 @@ -272,7 +272,7 @@ self.get_changeset(rev1) self.get_changeset(rev2) if path: - file_filter = mercurial.match.exact(path) + file_filter = mercurial.match.exact([safe_bytes(path)]) else: file_filter = None diff -r 0bca9e828db2 -r a04d6926d694 kallithea/model/comment.py --- a/kallithea/model/comment.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/model/comment.py Wed Jun 17 21:52:16 2020 +0200 @@ -105,6 +105,7 @@ 'message': cs.message, 'message_short': h.shorter(cs.message, 50, firstline=True), 'cs_author': cs_author, + 'cs_author_username': cs_author.username, 'repo_name': repo.repo_name, 'short_id': h.short_id(revision), 'branch': cs.branch, diff -r 0bca9e828db2 -r a04d6926d694 kallithea/model/db.py --- a/kallithea/model/db.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/model/db.py Wed Jun 17 21:52:16 2020 +0200 @@ -46,7 +46,7 @@ import kallithea from kallithea.lib import ext_json from kallithea.lib.exceptions import DefaultUserException -from kallithea.lib.utils2 import (Optional, ascii_bytes, aslist, get_changeset_safe, get_clone_url, remove_prefix, safe_bytes, safe_int, safe_str, str2bool, +from kallithea.lib.utils2 import (Optional, asbool, ascii_bytes, aslist, get_changeset_safe, get_clone_url, remove_prefix, safe_bytes, safe_int, safe_str, urlreadable) from kallithea.lib.vcs import get_backend from kallithea.lib.vcs.backends.base import EmptyChangeset @@ -61,10 +61,6 @@ # BASE CLASSES #============================================================================== -def _hash_key(k): - return hashlib.md5(safe_bytes(k)).hexdigest() - - class BaseDbModel(object): """ Base Model for all classes @@ -185,7 +181,7 @@ 'str': safe_bytes, 'int': safe_int, 'unicode': safe_str, - 'bool': str2bool, + 'bool': asbool, 'list': functools.partial(aslist, sep=',') } DEFAULT_UPDATE_URL = '' @@ -1164,7 +1160,7 @@ if with_pullrequests: data['pull_requests'] = repo.pull_requests_other rc_config = Setting.get_app_settings() - repository_fields = str2bool(rc_config.get('repository_fields')) + repository_fields = asbool(rc_config.get('repository_fields')) if repository_fields: for f in self.extra_fields: data[f.field_key_prefixed] = f.field_value @@ -1556,18 +1552,12 @@ ('usergroup.write', _('Default user has write access to new user groups')), ('usergroup.admin', _('Default user has admin access to new user groups')), - ('hg.repogroup.create.false', _('Only admins can create repository groups')), - ('hg.repogroup.create.true', _('Non-admins can create repository groups')), - ('hg.usergroup.create.false', _('Only admins can create user groups')), ('hg.usergroup.create.true', _('Non-admins can create user groups')), ('hg.create.none', _('Only admins can create top level repositories')), ('hg.create.repository', _('Non-admins can create top level repositories')), - ('hg.create.write_on_repogroup.true', _('Repository creation enabled with write permission to a repository group')), - ('hg.create.write_on_repogroup.false', _('Repository creation disabled with write permission to a repository group')), - ('hg.fork.none', _('Only admins can fork repositories')), ('hg.fork.repository', _('Non-admins can fork repositories')), @@ -1585,7 +1575,6 @@ 'group.read', 'usergroup.read', 'hg.create.repository', - 'hg.create.write_on_repogroup.true', 'hg.fork.repository', 'hg.register.manual_activate', 'hg.extern_activate.auto', @@ -1610,9 +1599,6 @@ 'usergroup.write': 3, 'usergroup.admin': 4, - 'hg.repogroup.create.false': 0, - 'hg.repogroup.create.true': 1, - 'hg.usergroup.create.false': 0, 'hg.usergroup.create.true': 1, @@ -1622,9 +1608,6 @@ 'hg.create.none': 0, 'hg.create.repository': 1, - 'hg.create.write_on_repogroup.false': 0, - 'hg.create.write_on_repogroup.true': 1, - 'hg.register.none': 0, 'hg.register.manual_activate': 1, 'hg.register.auto_activate': 2, diff -r 0bca9e828db2 -r a04d6926d694 kallithea/model/forms.py --- a/kallithea/model/forms.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/model/forms.py Wed Jun 17 21:52:16 2020 +0200 @@ -396,7 +396,7 @@ def DefaultPermissionsForm(repo_perms_choices, group_perms_choices, user_group_perms_choices, create_choices, - create_on_write_choices, repo_group_create_choices, + repo_group_create_choices, user_group_create_choices, fork_choices, register_choices, extern_activate_choices): class _DefaultPermissionsForm(formencode.Schema): @@ -411,9 +411,7 @@ default_user_group_perm = v.OneOf(user_group_perms_choices) default_repo_create = v.OneOf(create_choices) - create_on_write = v.OneOf(create_on_write_choices) default_user_group_create = v.OneOf(user_group_create_choices) - #default_repo_group_create = v.OneOf(repo_group_create_choices) #not impl. yet default_fork = v.OneOf(fork_choices) default_register = v.OneOf(register_choices) diff -r 0bca9e828db2 -r a04d6926d694 kallithea/model/notification.py --- a/kallithea/model/notification.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/model/notification.py Wed Jun 17 21:52:16 2020 +0200 @@ -126,12 +126,18 @@ email_html_body = EmailNotificationModel() \ .get_email_tmpl(type_, 'html', **html_kwargs) - # don't send email to person who created this comment - rec_objs = set(recipients_objs).difference(set([created_by_obj])) + # don't send email to the person who caused the notification, except for + # notifications about new pull requests where the author is explicitly + # added. + rec_mails = set(obj.email for obj in recipients_objs) + if type_ == NotificationModel.TYPE_PULL_REQUEST: + rec_mails.add(created_by_obj.email) + else: + rec_mails.discard(created_by_obj.email) - # send email with notification to all other participants - for rec in rec_objs: - tasks.send_email([rec.email], email_subject, email_txt_body, + # send email with notification to participants + for rec_mail in sorted(rec_mails): + tasks.send_email([rec_mail], email_subject, email_txt_body, email_html_body, headers, from_name=created_by_obj.full_name_or_username) @@ -159,7 +165,7 @@ self.TYPE_PULL_REQUEST_COMMENT: 'pull_request_comment', } self._subj_map = { - self.TYPE_CHANGESET_COMMENT: _('[Comment] %(repo_name)s changeset %(short_id)s "%(message_short)s" on %(branch)s'), + self.TYPE_CHANGESET_COMMENT: _('[Comment] %(repo_name)s changeset %(short_id)s "%(message_short)s" on %(branch)s by %(cs_author_username)s'), self.TYPE_MESSAGE: 'Test Message', # self.TYPE_PASSWORD_RESET self.TYPE_REGISTRATION: _('New user %(new_username)s registered'), diff -r 0bca9e828db2 -r a04d6926d694 kallithea/model/permission.py --- a/kallithea/model/permission.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/model/permission.py Wed Jun 17 21:52:16 2020 +0200 @@ -31,7 +31,7 @@ from sqlalchemy.exc import DatabaseError -from kallithea.lib.utils2 import str2bool +from kallithea.lib.utils2 import asbool from kallithea.model.db import Permission, Session, User, UserRepoGroupToPerm, UserRepoToPerm, UserToPerm, UserUserGroupToPerm @@ -97,7 +97,7 @@ try: # stage 1 set anonymous access if perm_user.is_default_user: - perm_user.active = str2bool(form_result['anonymous']) + perm_user.active = asbool(form_result['anonymous']) # stage 2 reset defaults and set them from form data def _make_new(usr, perm_name): @@ -119,8 +119,6 @@ 'default_group_perm', 'default_user_group_perm', 'default_repo_create', - 'create_on_write', # special case for create repos on write access to group - #'default_repo_group_create', # not implemented yet 'default_user_group_create', 'default_fork', 'default_register', diff -r 0bca9e828db2 -r a04d6926d694 kallithea/model/scm.py --- a/kallithea/model/scm.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/model/scm.py Wed Jun 17 21:52:16 2020 +0200 @@ -748,7 +748,7 @@ log.debug('skipping writing hook file') -def AvailableRepoGroupChoices(top_perms, repo_group_perm_level, extras=()): +def AvailableRepoGroupChoices(repo_group_perm_level, extras=()): """Return group_id,string tuples with choices for all the repo groups where the user has the necessary permissions. @@ -759,7 +759,7 @@ groups.append(None) else: groups = list(RepoGroupList(groups, perm_level=repo_group_perm_level)) - if top_perms and HasPermissionAny(*top_perms)('available repo groups'): + if HasPermissionAny('hg.create.repository')('available repo groups'): groups.append(None) for extra in extras: if not any(rg == extra for rg in groups): diff -r 0bca9e828db2 -r a04d6926d694 kallithea/model/ssh_key.py --- a/kallithea/model/ssh_key.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/model/ssh_key.py Wed Jun 17 21:52:16 2020 +0200 @@ -29,7 +29,7 @@ from tg.i18n import ugettext as _ from kallithea.lib import ssh -from kallithea.lib.utils2 import str2bool +from kallithea.lib.utils2 import asbool from kallithea.lib.vcs.exceptions import RepositoryError from kallithea.model.db import User, UserSshKeys from kallithea.model.meta import Session @@ -95,7 +95,7 @@ return user_ssh_keys def write_authorized_keys(self): - if not str2bool(config.get('ssh_enabled', False)): + if not asbool(config.get('ssh_enabled', False)): log.error("Will not write SSH authorized_keys file - ssh_enabled is not configured") return authorized_keys = config.get('ssh_authorized_keys') diff -r 0bca9e828db2 -r a04d6926d694 kallithea/model/validators.py --- a/kallithea/model/validators.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/model/validators.py Wed Jun 17 21:52:16 2020 +0200 @@ -32,7 +32,7 @@ from kallithea.lib.compat import OrderedSet from kallithea.lib.exceptions import InvalidCloneUriException, LdapImportError from kallithea.lib.utils import is_valid_repo_uri -from kallithea.lib.utils2 import aslist, repo_name_slug, str2bool +from kallithea.lib.utils2 import asbool, aslist, repo_name_slug from kallithea.model import db from kallithea.model.db import RepoGroup, Repository, User, UserGroup @@ -456,12 +456,11 @@ gr_name = gr.group_name if gr is not None else None # None means ROOT location # create repositories with write permission on group is set to true - create_on_write = HasPermissionAny('hg.create.write_on_repogroup.true')() group_admin = HasRepoGroupPermissionLevel('admin')(gr_name, 'can write into group validator') group_write = HasRepoGroupPermissionLevel('write')(gr_name, 'can write into group validator') - forbidden = not (group_admin or (group_write and create_on_write)) + forbidden = not (group_admin or group_write) can_create_repos = HasPermissionAny('hg.admin', 'hg.create.repository') gid = (old_data['repo_group'].get('group_id') if (old_data and 'repo_group' in old_data) else None) @@ -568,7 +567,7 @@ 'g': 'users_group' }[k[0]] if member_name == User.DEFAULT_USER_NAME: - if str2bool(value.get('repo_private')): + if asbool(value.get('repo_private')): # set none for default when updating to # private repo protects against form manipulation v = EMPTY_PERM diff -r 0bca9e828db2 -r a04d6926d694 kallithea/templates/admin/permissions/permissions_globals.html --- a/kallithea/templates/admin/permissions/permissions_globals.html Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/templates/admin/permissions/permissions_globals.html Wed Jun 17 21:52:16 2020 +0200 @@ -58,13 +58,6 @@
- -
- ${h.select('create_on_write','',c.repo_create_on_write_choices,class_='form-control')} - ${_('With this, write permission to a repository group allows creating repositories inside that group. Without this, group write permissions mean nothing.')} -
-
-
${h.select('default_user_group_create','',c.user_group_create_choices,class_='form-control')} diff -r 0bca9e828db2 -r a04d6926d694 kallithea/templates/index_base.html --- a/kallithea/templates/index_base.html Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/templates/index_base.html Wed Jun 17 21:52:16 2020 +0200 @@ -16,11 +16,10 @@ <% gr_name = c.group.group_name if c.group else None # create repositories with write permission on group is set to true - create_on_write = h.HasPermissionAny('hg.create.write_on_repogroup.true')() group_admin = h.HasRepoGroupPermissionLevel('admin')(gr_name, 'can write into group index page') group_write = h.HasRepoGroupPermissionLevel('write')(gr_name, 'can write into group index page') %> - %if h.HasPermissionAny('hg.admin','hg.create.repository')() or (group_admin or (group_write and create_on_write)): + %if h.HasPermissionAny('hg.admin','hg.create.repository')() or group_admin or group_write: %if c.group: ${_('Add Repository')} %if h.HasPermissionAny('hg.admin')() or h.HasRepoGroupPermissionLevel('admin')(c.group.group_name): diff -r 0bca9e828db2 -r a04d6926d694 kallithea/tests/models/test_diff_parsers.py --- a/kallithea/tests/models/test_diff_parsers.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/tests/models/test_diff_parsers.py Wed Jun 17 21:52:16 2020 +0200 @@ -295,7 +295,7 @@ l.append('%(action)-7s %(new_lineno)3s %(old_lineno)3s %(line)r\n' % d) s = ''.join(l) assert s == r''' -context ... ... '@@ -51,6 +51,13 @@\n' +context '@@ -51,6 +51,13 @@\n' unmod 51 51 '\tbegin();\n' unmod 52 52 '\t\n' add 53 '\tint foo;\n' diff -r 0bca9e828db2 -r a04d6926d694 kallithea/tests/models/test_dump_html_mails.ref.html --- a/kallithea/tests/models/test_dump_html_mails.ref.html Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/tests/models/test_dump_html_mails.ref.html Wed Jun 17 21:52:16 2020 +0200 @@ -7,7 +7,7 @@
 From: u1 u1 
 To: u2@example.com
-Subject: [Comment] repo/name changeset cafe1234 "This changeset did something cl..." on brunch
+Subject: [Comment] repo/name changeset cafe1234 "This changeset did something cl..." on brunch by u2
 

http://comment.org
@@ -166,7 +166,7 @@
 
 From: u1 u1 
 To: u2@example.com
-Subject: [Comment] repo/name changeset cafe1234 "This changeset did something cl..." on brunch
+Subject: [Comment] repo/name changeset cafe1234 "This changeset did something cl..." on brunch by u2
 

http://comment.org
@@ -325,7 +325,7 @@
 
 From: u1 u1 
 To: u2@example.com
-Subject: [Approved: Comment] repo/name changeset cafe1234 "This changeset did something cl..." on brunch
+Subject: [Approved: Comment] repo/name changeset cafe1234 "This changeset did something cl..." on brunch by u2
 

http://comment.org
@@ -502,7 +502,7 @@
 
 From: u1 u1 
 To: u2@example.com
-Subject: [Approved: Comment] repo/name changeset cafe1234 "This changeset did something cl..." on brunch
+Subject: [Approved: Comment] repo/name changeset cafe1234 "This changeset did something cl..." on brunch by u2
 

http://comment.org
@@ -882,6 +882,197 @@
 

pull_request, is_mention=False

 From: u1 u1 
+To: u1@example.com
+Subject: [Review] repo/name PR #7 "The Title" from devbranch by u2
+
+
+
http://pr.org/7
+
+Added as Reviewer of Pull Request #7 "The Title" by Requesting User (root)
+
+
+Pull request #7 "The Title" by u2 u3 (u2)
+from https://dev.org/repo branch devbranch
+to http://mainline.com/repo branch trunk
+
+
+Description:
+
+This PR is 'awesome' because it does 
+ - please approve indented!
+
+
+Changesets:
+
+Introduce one and two
+Make one plus two equal tree
+
+
+View Pull Request: http://pr.org/7
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + +
+ Added as Reviewer of Pull Request #7 "The Title" by Requesting User (root) +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+ Pull request + #7 "The Title" + by + u2 u3 (u2). +
+
+ from + https://dev.org/repo + branch + devbranch +
+ to + http://mainline.com/repo + branch + trunk +
+
+
+ Description: +
+
+ + + + + + + + + + + + +
+
This PR is 'awesome' because it does <stuff>
- please approve indented!
+
+
+
Changesets:
+
+ +
+
+ + + + + + + +
+ +
+ + View Pull Request + +
+
+
+
+
+
+
+ + +
+
+

pull_request, is_mention=False

+
+From: u1 u1 
 To: u2@example.com
 Subject: [Review] repo/name PR #7 "The Title" from devbranch by u2
 
@@ -1073,6 +1264,197 @@

pull_request, is_mention=True

 From: u1 u1 
+To: u1@example.com
+Subject: [Review] repo/name PR #7 "The Title" from devbranch by u2
+
+
+
http://pr.org/7
+
+Mention on Pull Request #7 "The Title" by Requesting User (root)
+
+
+Pull request #7 "The Title" by u2 u3 (u2)
+from https://dev.org/repo branch devbranch
+to http://mainline.com/repo branch trunk
+
+
+Description:
+
+This PR is 'awesome' because it does 
+ - please approve indented!
+
+
+Changesets:
+
+Introduce one and two
+Make one plus two equal tree
+
+
+View Pull Request: http://pr.org/7
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + +
+ Mention on Pull Request #7 "The Title" by Requesting User (root) +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+ Pull request + #7 "The Title" + by + u2 u3 (u2). +
+
+ from + https://dev.org/repo + branch + devbranch +
+ to + http://mainline.com/repo + branch + trunk +
+
+
+ Description: +
+
+ + + + + + + + + + + + +
+
This PR is 'awesome' because it does <stuff>
- please approve indented!
+
+
+
Changesets:
+
+ +
+
+ + + + + + + +
+ +
+ + View Pull Request + +
+
+
+
+
+
+
+ + +
+
+

pull_request, is_mention=True

+
+From: u1 u1 
 To: u2@example.com
 Subject: [Review] repo/name PR #7 "The Title" from devbranch by u2
 
diff -r 0bca9e828db2 -r a04d6926d694 kallithea/tests/models/test_notifications.py --- a/kallithea/tests/models/test_notifications.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/tests/models/test_notifications.py Wed Jun 17 21:52:16 2020 +0200 @@ -103,6 +103,7 @@ status_change=[None, 'Approved'], cs_target_repo='http://example.com/repo_target', cs_url='http://changeset.com', + cs_author_username=User.get(self.u2).username, cs_author=User.get(self.u2))), (NotificationModel.TYPE_MESSAGE, 'This is the \'body\' of the "test" message\n - nothing interesting here except indentation.', diff -r 0bca9e828db2 -r a04d6926d694 kallithea/tests/models/test_permissions.py --- a/kallithea/tests/models/test_permissions.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/tests/models/test_permissions.py Wed Jun 17 21:52:16 2020 +0200 @@ -290,7 +290,7 @@ 'hg.register.manual_activate', 'hg.extern_activate.auto', 'repository.read', 'group.read', - 'usergroup.read', 'hg.create.write_on_repogroup.true']) + 'usergroup.read']) def test_inherit_sad_permissions_from_default_user(self): user_model = UserModel() @@ -307,7 +307,7 @@ 'hg.register.manual_activate', 'hg.extern_activate.auto', 'repository.read', 'group.read', - 'usergroup.read', 'hg.create.write_on_repogroup.true']) + 'usergroup.read']) def test_inherit_more_permissions_from_default_user(self): user_model = UserModel() @@ -333,7 +333,7 @@ 'hg.register.manual_activate', 'hg.extern_activate.auto', 'repository.read', 'group.read', - 'usergroup.read', 'hg.create.write_on_repogroup.true']) + 'usergroup.read']) def test_inherit_less_permissions_from_default_user(self): user_model = UserModel() @@ -359,7 +359,7 @@ 'hg.register.manual_activate', 'hg.extern_activate.auto', 'repository.read', 'group.read', - 'usergroup.read', 'hg.create.write_on_repogroup.true']) + 'usergroup.read']) def test_inactive_user_group_does_not_affect_global_permissions(self): # Add user to inactive user group, set specific permissions on user @@ -391,7 +391,7 @@ 'hg.extern_activate.auto', 'repository.read', 'group.read', 'usergroup.read', - 'hg.create.write_on_repogroup.true']) + ]) def test_inactive_user_group_does_not_affect_global_permissions_inverse(self): # Add user to inactive user group, set specific permissions on user @@ -423,7 +423,7 @@ 'hg.extern_activate.auto', 'repository.read', 'group.read', 'usergroup.read', - 'hg.create.write_on_repogroup.true']) + ]) def test_inactive_user_group_does_not_affect_repo_permissions(self): self.ug1 = fixture.create_user_group('G1') diff -r 0bca9e828db2 -r a04d6926d694 kallithea/tests/other/test_libs.py --- a/kallithea/tests/other/test_libs.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/tests/other/test_libs.py Wed Jun 17 21:52:16 2020 +0200 @@ -119,12 +119,10 @@ ('F', False), ('FALSE', False), ('0', False), - ('-1', False), - ('', False) ]) - def test_str2bool(self, str_bool, expected): - from kallithea.lib.utils2 import str2bool - assert str2bool(str_bool) == expected + def test_asbool(self, str_bool, expected): + from kallithea.lib.utils2 import asbool + assert asbool(str_bool) == expected def test_mention_extractor(self): from kallithea.lib.utils2 import extract_mentioned_usernames diff -r 0bca9e828db2 -r a04d6926d694 kallithea/tests/scripts/manual_test_concurrency.py --- a/kallithea/tests/scripts/manual_test_concurrency.py Thu Jun 11 20:50:26 2020 +0200 +++ b/kallithea/tests/scripts/manual_test_concurrency.py Wed Jun 17 21:52:16 2020 +0200 @@ -37,7 +37,7 @@ from paste.deploy import appconfig from sqlalchemy import engine_from_config -from kallithea.config.environment import load_environment +import kallithea.config.application from kallithea.lib.auth import get_crypt_password from kallithea.model import meta from kallithea.model.base import init_model @@ -47,7 +47,7 @@ rel_path = dirname(dirname(dirname(dirname(os.path.abspath(__file__))))) conf = appconfig('config:development.ini', relative_to=rel_path) -load_environment(conf.global_conf, conf.local_conf) +kallithea.config.application.make_app(conf.global_conf, **conf.local_conf) USER = TEST_USER_ADMIN_LOGIN PASS = TEST_USER_ADMIN_PASS diff -r 0bca9e828db2 -r a04d6926d694 setup.py --- a/setup.py Thu Jun 11 20:50:26 2020 +0200 +++ b/setup.py Wed Jun 17 21:52:16 2020 +0200 @@ -53,7 +53,7 @@ "FormEncode >= 1.3.1, < 1.4", "SQLAlchemy >= 1.2.9, < 1.4", "Mako >= 0.9.1, < 1.2", - "Pygments >= 2.2.0, < 2.6", + "Pygments >= 2.2.0, < 2.7", "Whoosh >= 2.7.1, < 2.8", "celery >= 4.3, < 4.5, != 4.4.4", # 4.4.4 is broken due to unexpressed dependency on 'future', see https://github.com/celery/celery/pull/6146 "Babel >= 1.3, < 2.9", @@ -65,7 +65,7 @@ "dulwich >= 0.19.0, < 0.20", "mercurial >= 5.2, < 5.5", "decorator >= 4.2.1, < 4.5", - "Paste >= 2.0.3, < 3.4", + "Paste >= 2.0.3, < 3.5", "bleach >= 3.0, < 3.1.4", "Click >= 7.0, < 8", "ipaddr >= 2.2.0, < 2.3", @@ -156,6 +156,6 @@ kallithea-cli = kallithea.bin.kallithea_cli:cli [paste.app_factory] - main = kallithea.config.middleware:make_app + main = kallithea.config.application:make_app """, )