Mercurial > kallithea
changeset 5551:18428eab23e1
Merge stable
author | Mads Kiilerich <madski@unity3d.com> |
---|---|
date | Mon, 12 Oct 2015 18:55:41 +0200 |
parents | 23a86f1c33a1 (diff) 03975e4a8532 (current diff) |
children | 1013437c997a |
files | |
diffstat | 43 files changed, 467 insertions(+), 262 deletions(-) [+] |
line wrap: on
line diff
--- a/development.ini Sun Oct 11 22:09:42 2015 +0200 +++ b/development.ini Mon Oct 12 18:55:41 2015 +0200 @@ -163,6 +163,7 @@ #cheaper-step = 1 ## COMMON ## +#host = 127.0.0.1 host = 0.0.0.0 port = 5000 @@ -280,12 +281,6 @@ #issue_server_link_wiki = https://wiki.example.com/{id} #issue_prefix_wiki = WIKI- -## instance-id prefix -## a prefix key for this instance used for cache invalidation when running -## multiple instances of kallithea, make sure it's globally unique for -## all running kallithea instances. Leave empty if you don't use it -instance_id = - ## alternative return HTTP header for failed authentication. Default HTTP ## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with ## handling that. Set this variable to 403 to return HTTPForbidden @@ -560,16 +555,16 @@ class = StreamHandler args = (sys.stderr,) #level = INFO +level = DEBUG #formatter = generic -level = DEBUG formatter = color_formatter [handler_console_sql] class = StreamHandler args = (sys.stderr,) #level = WARN +level = DEBUG #formatter = generic -level = DEBUG formatter = color_formatter_sql ################
--- a/docs/setup.rst Sun Oct 11 22:09:42 2015 +0200 +++ b/docs/setup.rst Mon Oct 12 18:55:41 2015 +0200 @@ -746,11 +746,6 @@ When running apache as root, please make sure it doesn't run Kallithea as root, for examply by adding: ``user=www-data group=www-data`` to the configuration. -.. note:: - If running Kallithea in multiprocess mode, - make sure you set ``instance_id = *`` in the configuration so each process - gets it's own cache invalidation key. - Example WSGI dispatch script: .. code-block:: python
--- a/docs/usage/performance.rst Sun Oct 11 22:09:42 2015 +0200 +++ b/docs/usage/performance.rst Mon Oct 12 18:55:41 2015 +0200 @@ -38,7 +38,6 @@ scaled horizontally on one (recommended) or multiple machines. In order to scale horizontally you need to do the following: - - Each instance needs its own .ini file and unique ``instance_id`` set. - Each instance's ``data`` storage needs to be configured to be stored on a shared disk storage, preferably together with repositories. This ``data`` dir contains template caches, sessions, whoosh index and is used for
--- a/kallithea/bin/template.ini.mako Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/bin/template.ini.mako Mon Oct 12 18:55:41 2015 +0200 @@ -278,12 +278,6 @@ #issue_server_link_wiki = https://wiki.example.com/{id} #issue_prefix_wiki = WIKI- -<%text>## instance-id prefix</%text> -<%text>## a prefix key for this instance used for cache invalidation when running</%text> -<%text>## multiple instances of kallithea, make sure it's globally unique for</%text> -<%text>## all running kallithea instances. Leave empty if you don't use it</%text> -instance_id = - <%text>## alternative return HTTP header for failed authentication. Default HTTP</%text> <%text>## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with</%text> <%text>## handling that. Set this variable to 403 to return HTTPForbidden</%text>
--- a/kallithea/config/deployment.ini_tmpl Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/config/deployment.ini_tmpl Mon Oct 12 18:55:41 2015 +0200 @@ -274,12 +274,6 @@ #issue_server_link_wiki = https://wiki.example.com/{id} #issue_prefix_wiki = WIKI- -## instance-id prefix -## a prefix key for this instance used for cache invalidation when running -## multiple instances of kallithea, make sure it's globally unique for -## all running kallithea instances. Leave empty if you don't use it -instance_id = - ## alternative return HTTP header for failed authentication. Default HTTP ## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with ## handling that. Set this variable to 403 to return HTTPForbidden
--- a/kallithea/config/environment.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/config/environment.py Mon Oct 12 18:55:41 2015 +0200 @@ -118,7 +118,7 @@ config['base_path'] = repos_path set_app_settings(config) - instance_id = kallithea.CONFIG.get('instance_id') + 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
--- a/kallithea/controllers/admin/auth_settings.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/controllers/admin/auth_settings.py Mon Oct 12 18:55:41 2015 +0200 @@ -28,8 +28,8 @@ import traceback from pylons import request, tmpl_context as c, url -from pylons.controllers.util import redirect from pylons.i18n.translation import _ +from webob.exc import HTTPFound from kallithea.lib import helpers as h from kallithea.lib.compat import formatted_json @@ -146,4 +146,4 @@ h.flash(_('error occurred during update of auth settings'), category='error') - return redirect(url('auth_home')) + raise HTTPFound(location=url('auth_home'))
--- a/kallithea/controllers/admin/defaults.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/controllers/admin/defaults.py Mon Oct 12 18:55:41 2015 +0200 @@ -31,8 +31,8 @@ from formencode import htmlfill from pylons import request, tmpl_context as c, url -from pylons.controllers.util import redirect from pylons.i18n.translation import _ +from webob.exc import HTTPFound from kallithea.lib import helpers as h from kallithea.lib.auth import LoginRequired, HasPermissionAllDecorator @@ -112,7 +112,7 @@ h.flash(_('Error occurred during update of defaults'), category='error') - return redirect(url('defaults')) + raise HTTPFound(location=url('defaults')) def delete(self, id): """DELETE /defaults/id: Delete an existing item"""
--- a/kallithea/controllers/admin/gists.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/controllers/admin/gists.py Mon Oct 12 18:55:41 2015 +0200 @@ -31,8 +31,8 @@ import formencode.htmlfill from pylons import request, response, tmpl_context as c, url -from pylons.controllers.util import redirect from pylons.i18n.translation import _ +from webob.exc import HTTPFound, HTTPNotFound, HTTPForbidden from kallithea.model.forms import GistForm from kallithea.model.gist import GistModel @@ -44,7 +44,6 @@ from kallithea.lib.utils import jsonify from kallithea.lib.utils2 import safe_int, time_to_datetime from kallithea.lib.helpers import Page -from webob.exc import HTTPNotFound, HTTPForbidden from sqlalchemy.sql.expression import or_ from kallithea.lib.vcs.exceptions import VCSError, NodeNotChangedError @@ -70,7 +69,7 @@ def index(self): """GET /admin/gists: All items in the collection""" # url('gists') - not_default_user = c.authuser.username != User.DEFAULT_USER + not_default_user = not c.authuser.is_default_user c.show_private = request.GET.get('private') and not_default_user c.show_public = request.GET.get('public') and not_default_user @@ -144,8 +143,8 @@ except Exception as e: log.error(traceback.format_exc()) h.flash(_('Error occurred during gist creation'), category='error') - return redirect(url('new_gist')) - return redirect(url('gist', gist_id=new_gist_id)) + raise HTTPFound(location=url('new_gist')) + raise HTTPFound(location=url('gist', gist_id=new_gist_id)) @LoginRequired() @NotAnonymous() @@ -185,7 +184,7 @@ else: raise HTTPForbidden() - return redirect(url('gists')) + raise HTTPFound(location=url('gists')) @LoginRequired() def show(self, gist_id, revision='tip', format='html', f_path=None): @@ -270,7 +269,7 @@ h.flash(_('Error occurred during update of gist %s') % gist_id, category='error') - return redirect(url('gist', gist_id=gist_id)) + raise HTTPFound(location=url('gist', gist_id=gist_id)) return rendered
--- a/kallithea/controllers/admin/my_account.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/controllers/admin/my_account.py Mon Oct 12 18:55:41 2015 +0200 @@ -32,8 +32,8 @@ from sqlalchemy import func from formencode import htmlfill from pylons import request, tmpl_context as c, url -from pylons.controllers.util import redirect from pylons.i18n.translation import _ +from webob.exc import HTTPFound from kallithea import EXTERN_TYPE_INTERNAL from kallithea.lib import helpers as h @@ -69,7 +69,7 @@ if c.user.username == User.DEFAULT_USER: h.flash(_("You can't edit this user since it's" " crucial for entire application"), category='warning') - return redirect(url('users')) + raise HTTPFound(location=url('users')) c.EXTERN_TYPE_INTERNAL = EXTERN_TYPE_INTERNAL def _load_my_repos_data(self, watched=False): @@ -144,7 +144,7 @@ h.flash(_('Error occurred during update of user %s') \ % form_result.get('username'), category='error') if update: - return redirect('my_account') + raise HTTPFound(location='my_account') return htmlfill.render( render('admin/my_account/my_account.html'), defaults=defaults, @@ -225,7 +225,7 @@ log.error(traceback.format_exc()) h.flash(_('An error occurred during email saving'), category='error') - return redirect(url('my_account_emails')) + raise HTTPFound(location=url('my_account_emails')) def my_account_emails_delete(self): email_id = request.POST.get('del_email_id') @@ -233,7 +233,7 @@ user_model.delete_extra_email(self.authuser.user_id, email_id) Session().commit() h.flash(_("Removed email from user"), category='success') - return redirect(url('my_account_emails')) + raise HTTPFound(location=url('my_account_emails')) def my_account_api_keys(self): c.active = 'api_keys' @@ -257,7 +257,7 @@ ApiKeyModel().create(self.authuser.user_id, description, lifetime) Session().commit() h.flash(_("API key successfully created"), category='success') - return redirect(url('my_account_api_keys')) + raise HTTPFound(location=url('my_account_api_keys')) def my_account_api_keys_delete(self): api_key = request.POST.get('del_api_key') @@ -274,4 +274,4 @@ Session().commit() h.flash(_("API key successfully deleted"), category='success') - return redirect(url('my_account_api_keys')) + raise HTTPFound(location=url('my_account_api_keys'))
--- a/kallithea/controllers/admin/notifications.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/controllers/admin/notifications.py Mon Oct 12 18:55:41 2015 +0200 @@ -30,8 +30,7 @@ from pylons import request from pylons import tmpl_context as c -from pylons.controllers.util import abort -from webob.exc import HTTPBadRequest +from webob.exc import HTTPBadRequest, HTTPForbidden from kallithea.model.db import Notification from kallithea.model.notification import NotificationModel @@ -168,7 +167,7 @@ return render('admin/notifications/show_notification.html') - return abort(403) + raise HTTPForbidden() def edit(self, notification_id, format='html'): """GET /_admin/notifications/id/edit: Form to edit an existing item"""
--- a/kallithea/controllers/admin/permissions.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/controllers/admin/permissions.py Mon Oct 12 18:55:41 2015 +0200 @@ -32,8 +32,8 @@ from formencode import htmlfill from pylons import request, tmpl_context as c, url -from pylons.controllers.util import redirect from pylons.i18n.translation import _ +from webob.exc import HTTPFound from kallithea.lib import helpers as h from kallithea.lib.auth import LoginRequired, HasPermissionAllDecorator @@ -139,7 +139,7 @@ h.flash(_('Error occurred during update of permissions'), category='error') - return redirect(url('admin_permissions')) + raise HTTPFound(location=url('admin_permissions')) c.user = User.get_default_user() defaults = {'anonymous': c.user.active}
--- a/kallithea/controllers/admin/repo_groups.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/controllers/admin/repo_groups.py Mon Oct 12 18:55:41 2015 +0200 @@ -33,8 +33,8 @@ from formencode import htmlfill from pylons import request, tmpl_context as c, url -from pylons.controllers.util import abort, redirect from pylons.i18n.translation import _, ungettext +from webob.exc import HTTPFound, HTTPForbidden, HTTPNotFound, HTTPInternalServerError import kallithea from kallithea.lib import helpers as h @@ -49,7 +49,6 @@ from kallithea.model.forms import RepoGroupForm, RepoGroupPermsForm from kallithea.model.meta import Session from kallithea.model.repo import RepoModel -from webob.exc import HTTPInternalServerError, HTTPNotFound from kallithea.lib.utils2 import safe_int from sqlalchemy.sql.expression import func @@ -189,10 +188,10 @@ % request.POST.get('group_name'), category='error') parent_group_id = form_result['group_parent_id'] #TODO: maybe we should get back to the main view, not the admin one - return redirect(url('repos_groups', parent_group=parent_group_id)) + raise HTTPFound(location=url('repos_groups', parent_group=parent_group_id)) h.flash(_('Created repository group %s') % gr.group_name, category='success') - return redirect(url('repos_group_home', group_name=gr.group_name)) + raise HTTPFound(location=url('repos_group_home', group_name=gr.group_name)) def new(self): """GET /repo_groups/new: Form to create a new item""" @@ -209,7 +208,7 @@ if HasRepoGroupPermissionAll('group.admin')(group_name, 'group create'): pass else: - return abort(403) + raise HTTPForbidden() self.__load_defaults() return render('admin/repo_groups/repo_group_add.html') @@ -266,7 +265,7 @@ h.flash(_('Error occurred during update of repository group %s') \ % request.POST.get('group_name'), category='error') - return redirect(url('edit_repo_group', group_name=group_name)) + raise HTTPFound(location=url('edit_repo_group', group_name=group_name)) @HasRepoGroupPermissionAnyDecorator('group.admin') def delete(self, group_name): @@ -283,13 +282,13 @@ if repos: h.flash(_('This group contains %s repositories and cannot be ' 'deleted') % len(repos), category='warning') - return redirect(url('repos_groups')) + raise HTTPFound(location=url('repos_groups')) children = gr.children.all() if children: h.flash(_('This group contains %s subgroups and cannot be deleted' % (len(children))), category='warning') - return redirect(url('repos_groups')) + raise HTTPFound(location=url('repos_groups')) try: RepoGroupModel().delete(group_name) @@ -303,8 +302,8 @@ % group_name, category='error') if gr.parent_group: - return redirect(url('repos_group_home', group_name=gr.parent_group.group_name)) - return redirect(url('repos_groups')) + raise HTTPFound(location=url('repos_group_home', group_name=gr.parent_group.group_name)) + raise HTTPFound(location=url('repos_groups')) def show_by_name(self, group_name): """ @@ -404,7 +403,7 @@ if self._revoke_perms_on_yourself(form_result): msg = _('Cannot revoke permission for yourself as admin') h.flash(msg, category='warning') - return redirect(url('edit_repo_group_perms', group_name=group_name)) + raise HTTPFound(location=url('edit_repo_group_perms', group_name=group_name)) recursive = form_result['recursive'] # iterate over all members(if in recursive mode) of this groups and # set the permissions ! @@ -418,7 +417,7 @@ # repo_name, self.ip_addr, self.sa) Session().commit() h.flash(_('Repository group permissions updated'), category='success') - return redirect(url('edit_repo_group_perms', group_name=group_name)) + raise HTTPFound(location=url('edit_repo_group_perms', group_name=group_name)) @HasRepoGroupPermissionAnyDecorator('group.admin') def delete_perms(self, group_name):
--- a/kallithea/controllers/admin/repos.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/controllers/admin/repos.py Mon Oct 12 18:55:41 2015 +0200 @@ -29,11 +29,10 @@ import traceback import formencode from formencode import htmlfill -from webob.exc import HTTPInternalServerError, HTTPForbidden, HTTPNotFound from pylons import request, tmpl_context as c, url -from pylons.controllers.util import redirect from pylons.i18n.translation import _ from sqlalchemy.sql.expression import func +from webob.exc import HTTPFound, HTTPInternalServerError, HTTPForbidden, HTTPNotFound from kallithea.lib import helpers as h from kallithea.lib.auth import LoginRequired, \ @@ -71,7 +70,7 @@ if repo_obj is None: h.not_mapped_error(repo_name) - return redirect(url('repos')) + raise HTTPFound(location=url('repos')) return repo_obj @@ -152,9 +151,9 @@ msg = (_('Error creating repository %s') % form_result.get('repo_name')) h.flash(msg, category='error') - return redirect(url('home')) + raise HTTPFound(location=url('home')) - return redirect(h.url('repo_creating_home', + raise HTTPFound(location=h.url('repo_creating_home', repo_name=form_result['repo_name_full'], task_id=task_id)) @@ -282,7 +281,7 @@ log.error(traceback.format_exc()) h.flash(_('Error occurred during update of repository %s') \ % repo_name, category='error') - return redirect(url('edit_repo', repo_name=changed_name)) + raise HTTPFound(location=url('edit_repo', repo_name=changed_name)) @HasRepoPermissionAllDecorator('repository.admin') def delete(self, repo_name): @@ -299,7 +298,7 @@ repo = repo_model.get_by_repo_name(repo_name) if not repo: h.not_mapped_error(repo_name) - return redirect(url('repos')) + raise HTTPFound(location=url('repos')) try: _forks = repo.forks.count() handle_forks = None @@ -327,8 +326,8 @@ category='error') if repo.group: - return redirect(url('repos_group_home', group_name=repo.group.group_name)) - return redirect(url('repos')) + raise HTTPFound(location=url('repos_group_home', group_name=repo.group.group_name)) + raise HTTPFound(location=url('repos')) @HasRepoPermissionAllDecorator('repository.admin') def edit(self, repo_name): @@ -372,7 +371,7 @@ # repo_name, self.ip_addr, self.sa) Session().commit() h.flash(_('Repository permissions updated'), category='success') - return redirect(url('edit_repo_perms', repo_name=repo_name)) + raise HTTPFound(location=url('edit_repo_perms', repo_name=repo_name)) def edit_permissions_revoke(self, repo_name): try: @@ -409,7 +408,7 @@ c.active = 'fields' if request.POST: - return redirect(url('repo_edit_fields')) + raise HTTPFound(location=url('repo_edit_fields')) return render('admin/repos/repo_edit.html') @HasRepoPermissionAllDecorator('repository.admin') @@ -431,7 +430,7 @@ if isinstance(e, formencode.Invalid): msg += ". " + e.msg h.flash(msg, category='error') - return redirect(url('edit_repo_fields', repo_name=repo_name)) + raise HTTPFound(location=url('edit_repo_fields', repo_name=repo_name)) @HasRepoPermissionAllDecorator('repository.admin') def delete_repo_field(self, repo_name, field_id): @@ -443,7 +442,7 @@ log.error(traceback.format_exc()) msg = _('An error occurred during removal of field') h.flash(msg, category='error') - return redirect(url('edit_repo_fields', repo_name=repo_name)) + raise HTTPFound(location=url('edit_repo_fields', repo_name=repo_name)) @HasRepoPermissionAllDecorator('repository.admin') def edit_advanced(self, repo_name): @@ -468,7 +467,7 @@ c.active = 'advanced' if request.POST: - return redirect(url('repo_edit_advanced')) + raise HTTPFound(location=url('repo_edit_advanced')) return htmlfill.render( render('admin/repos/repo_edit.html'), defaults=defaults, @@ -495,7 +494,7 @@ h.flash(_('An error occurred during setting this' ' repository in public journal'), category='error') - return redirect(url('edit_repo_advanced', repo_name=repo_name)) + raise HTTPFound(location=url('edit_repo_advanced', repo_name=repo_name)) @HasRepoPermissionAllDecorator('repository.admin') @@ -521,7 +520,7 @@ h.flash(_('An error occurred during this operation'), category='error') - return redirect(url('edit_repo_advanced', repo_name=repo_name)) + raise HTTPFound(location=url('edit_repo_advanced', repo_name=repo_name)) @HasRepoPermissionAllDecorator('repository.admin') def edit_advanced_locking(self, repo_name): @@ -542,7 +541,7 @@ log.error(traceback.format_exc()) h.flash(_('An error occurred during unlocking'), category='error') - return redirect(url('edit_repo_advanced', repo_name=repo_name)) + raise HTTPFound(location=url('edit_repo_advanced', repo_name=repo_name)) @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') def toggle_locking(self, repo_name): @@ -567,7 +566,7 @@ log.error(traceback.format_exc()) h.flash(_('An error occurred during unlocking'), category='error') - return redirect(url('summary_home', repo_name=repo_name)) + raise HTTPFound(location=url('summary_home', repo_name=repo_name)) @HasRepoPermissionAllDecorator('repository.admin') def edit_caches(self, repo_name): @@ -577,7 +576,7 @@ c.active = 'caches' if request.POST: try: - ScmModel().mark_for_invalidation(repo_name, delete=True) + ScmModel().mark_for_invalidation(repo_name) Session().commit() h.flash(_('Cache invalidation successful'), category='success') @@ -586,7 +585,7 @@ h.flash(_('An error occurred during cache invalidation'), category='error') - return redirect(url('edit_repo_caches', repo_name=c.repo_name)) + raise HTTPFound(location=url('edit_repo_caches', repo_name=c.repo_name)) return render('admin/repos/repo_edit.html') @HasRepoPermissionAllDecorator('repository.admin') @@ -603,7 +602,7 @@ log.error(traceback.format_exc()) h.flash(_('An error occurred during pull from remote location'), category='error') - return redirect(url('edit_repo_remote', repo_name=c.repo_name)) + raise HTTPFound(location=url('edit_repo_remote', repo_name=c.repo_name)) return render('admin/repos/repo_edit.html') @HasRepoPermissionAllDecorator('repository.admin') @@ -636,6 +635,6 @@ log.error(traceback.format_exc()) h.flash(_('An error occurred during deletion of repository stats'), category='error') - return redirect(url('edit_repo_statistics', repo_name=c.repo_name)) + raise HTTPFound(location=url('edit_repo_statistics', repo_name=c.repo_name)) return render('admin/repos/repo_edit.html')
--- a/kallithea/controllers/admin/settings.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/controllers/admin/settings.py Mon Oct 12 18:55:41 2015 +0200 @@ -31,8 +31,8 @@ from formencode import htmlfill from pylons import request, tmpl_context as c, url, config -from pylons.controllers.util import redirect from pylons.i18n.translation import _ +from webob.exc import HTTPFound from kallithea.lib import helpers as h from kallithea.lib.auth import LoginRequired, HasPermissionAllDecorator @@ -206,7 +206,7 @@ if invalidate_cache: log.debug('invalidating all repositories cache') for repo in Repository.get_all(): - ScmModel().mark_for_invalidation(repo.repo_name, delete=True) + ScmModel().mark_for_invalidation(repo.repo_name) filesystem_repos = ScmModel().repo_scan() added, removed = repo2db_mapper(filesystem_repos, rm_obsolete, @@ -218,7 +218,7 @@ for repo_name in added) or '-', ', '.join(h.escape(safe_unicode(repo_name)) for repo_name in removed) or '-')), category='success') - return redirect(url('admin_settings_mapping')) + raise HTTPFound(location=url('admin_settings_mapping')) defaults = Setting.get_app_settings() defaults.update(self._get_hg_ui_settings()) @@ -278,7 +278,7 @@ 'application settings'), category='error') - return redirect(url('admin_settings_global')) + raise HTTPFound(location=url('admin_settings_global')) defaults = Setting.get_app_settings() defaults.update(self._get_hg_ui_settings()) @@ -336,7 +336,7 @@ 'visualisation settings'), category='error') - return redirect(url('admin_settings_visual')) + raise HTTPFound(location=url('admin_settings_visual')) defaults = Setting.get_app_settings() defaults.update(self._get_hg_ui_settings()) @@ -359,7 +359,7 @@ 'Kallithea version: %s' % c.kallithea_version) if not test_email: h.flash(_('Please enter email address'), category='error') - return redirect(url('admin_settings_email')) + raise HTTPFound(location=url('admin_settings_email')) test_email_txt_body = EmailNotificationModel()\ .get_email_tmpl(EmailNotificationModel.TYPE_DEFAULT, @@ -374,7 +374,7 @@ test_email_txt_body, test_email_html_body) h.flash(_('Send email task created'), category='success') - return redirect(url('admin_settings_email')) + raise HTTPFound(location=url('admin_settings_email')) defaults = Setting.get_app_settings() defaults.update(self._get_hg_ui_settings()) @@ -425,7 +425,7 @@ h.flash(_('Error occurred during hook creation'), category='error') - return redirect(url('admin_settings_hooks')) + raise HTTPFound(location=url('admin_settings_hooks')) defaults = Setting.get_app_settings() defaults.update(self._get_hg_ui_settings()) @@ -449,7 +449,7 @@ full_index = request.POST.get('full_index', False) run_task(tasks.whoosh_index, repo_location, full_index) h.flash(_('Whoosh reindex task scheduled'), category='success') - return redirect(url('admin_settings_search')) + raise HTTPFound(location=url('admin_settings_search')) defaults = Setting.get_app_settings() defaults.update(self._get_hg_ui_settings())
--- a/kallithea/controllers/admin/user_groups.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/controllers/admin/user_groups.py Mon Oct 12 18:55:41 2015 +0200 @@ -31,8 +31,8 @@ from formencode import htmlfill from pylons import request, tmpl_context as c, url, config -from pylons.controllers.util import redirect from pylons.i18n.translation import _ +from webob.exc import HTTPFound from sqlalchemy.orm import joinedload from sqlalchemy.sql.expression import func @@ -163,7 +163,7 @@ h.flash(_('Error occurred during creation of user group %s') \ % request.POST.get('users_group_name'), category='error') - return redirect(url('users_groups')) + raise HTTPFound(location=url('users_groups')) @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true') def new(self, format='html'): @@ -224,7 +224,7 @@ h.flash(_('Error occurred during update of user group %s') \ % request.POST.get('users_group_name'), category='error') - return redirect(url('edit_users_group', id=id)) + raise HTTPFound(location=url('edit_users_group', id=id)) @HasUserGroupPermissionAnyDecorator('usergroup.admin') def delete(self, id): @@ -246,7 +246,7 @@ log.error(traceback.format_exc()) h.flash(_('An error occurred during deletion of user group'), category='error') - return redirect(url('users_groups')) + raise HTTPFound(location=url('users_groups')) def show(self, id, format='html'): """GET /user_groups/id: Show a specific item""" @@ -312,13 +312,13 @@ form['perms_updates']) except RepoGroupAssignmentError: h.flash(_('Target group cannot be the same'), category='error') - return redirect(url('edit_user_group_perms', id=id)) + raise HTTPFound(location=url('edit_user_group_perms', id=id)) #TODO: implement this #action_logger(self.authuser, 'admin_changed_repo_permissions', # repo_name, self.ip_addr, self.sa) Session().commit() h.flash(_('User group permissions updated'), category='success') - return redirect(url('edit_user_group_perms', id=id)) + raise HTTPFound(location=url('edit_user_group_perms', id=id)) @HasUserGroupPermissionAnyDecorator('usergroup.admin') def delete_perms(self, id): @@ -444,7 +444,7 @@ h.flash(_('An error occurred during permissions saving'), category='error') - return redirect(url('edit_user_group_default_perms', id=id)) + raise HTTPFound(location=url('edit_user_group_default_perms', id=id)) @HasUserGroupPermissionAnyDecorator('usergroup.admin') def edit_advanced(self, id):
--- a/kallithea/controllers/admin/users.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/controllers/admin/users.py Mon Oct 12 18:55:41 2015 +0200 @@ -31,10 +31,9 @@ from formencode import htmlfill from pylons import request, tmpl_context as c, url, config -from pylons.controllers.util import redirect from pylons.i18n.translation import _ from sqlalchemy.sql.expression import func -from webob.exc import HTTPNotFound +from webob.exc import HTTPFound, HTTPNotFound import kallithea from kallithea.lib.exceptions import DefaultUserException, \ @@ -148,7 +147,7 @@ log.error(traceback.format_exc()) h.flash(_('Error occurred during creation of user %s') \ % request.POST.get('username'), category='error') - return redirect(url('users')) + raise HTTPFound(location=url('users')) def new(self, format='html'): """GET /users/new: Form to create a new item""" @@ -201,7 +200,7 @@ log.error(traceback.format_exc()) h.flash(_('Error occurred during update of user %s') \ % form_result.get('username'), category='error') - return redirect(url('edit_user', id=id)) + raise HTTPFound(location=url('edit_user', id=id)) def delete(self, id): """DELETE /users/id: Delete an existing item""" @@ -222,7 +221,7 @@ log.error(traceback.format_exc()) h.flash(_('An error occurred during deletion of user'), category='error') - return redirect(url('users')) + raise HTTPFound(location=url('users')) def show(self, id, format='html'): """GET /users/id: Show a specific item""" @@ -306,7 +305,7 @@ ApiKeyModel().create(c.user.user_id, description, lifetime) Session().commit() h.flash(_("API key successfully created"), category='success') - return redirect(url('edit_user_api_keys', id=c.user.user_id)) + raise HTTPFound(location=url('edit_user_api_keys', id=c.user.user_id)) def delete_api_key(self, id): c.user = self._get_user_or_raise_if_default(id) @@ -324,7 +323,7 @@ Session().commit() h.flash(_("API key successfully deleted"), category='success') - return redirect(url('edit_user_api_keys', id=c.user.user_id)) + raise HTTPFound(location=url('edit_user_api_keys', id=c.user.user_id)) def update_account(self, id): pass @@ -387,7 +386,7 @@ log.error(traceback.format_exc()) h.flash(_('An error occurred during permissions saving'), category='error') - return redirect(url('edit_user_perms', id=id)) + raise HTTPFound(location=url('edit_user_perms', id=id)) def edit_emails(self, id): c.user = self._get_user_or_raise_if_default(id) @@ -420,7 +419,7 @@ log.error(traceback.format_exc()) h.flash(_('An error occurred during email saving'), category='error') - return redirect(url('edit_user_emails', id=id)) + raise HTTPFound(location=url('edit_user_emails', id=id)) def delete_email(self, id): """DELETE /user_emails_delete/id: Delete an existing item""" @@ -431,7 +430,7 @@ user_model.delete_extra_email(id, email_id) Session().commit() h.flash(_("Removed email from user"), category='success') - return redirect(url('edit_user_emails', id=id)) + raise HTTPFound(location=url('edit_user_emails', id=id)) def edit_ips(self, id): c.user = self._get_user_or_raise_if_default(id) @@ -470,8 +469,8 @@ category='error') if 'default_user' in request.POST: - return redirect(url('admin_permissions_ips')) - return redirect(url('edit_user_ips', id=id)) + raise HTTPFound(location=url('admin_permissions_ips')) + raise HTTPFound(location=url('edit_user_ips', id=id)) def delete_ip(self, id): """DELETE /user_ips_delete/id: Delete an existing item""" @@ -483,5 +482,5 @@ h.flash(_("Removed IP address from user whitelist"), category='success') if 'default_user' in request.POST: - return redirect(url('admin_permissions_ips')) - return redirect(url('edit_user_ips', id=id)) + raise HTTPFound(location=url('admin_permissions_ips')) + raise HTTPFound(location=url('edit_user_ips', id=id))
--- a/kallithea/controllers/changelog.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/controllers/changelog.py Mon Oct 12 18:55:41 2015 +0200 @@ -29,9 +29,8 @@ import traceback from pylons import request, url, session, tmpl_context as c -from pylons.controllers.util import redirect from pylons.i18n.translation import _ -from webob.exc import HTTPNotFound, HTTPBadRequest +from webob.exc import HTTPFound, HTTPNotFound, HTTPBadRequest import kallithea.lib.helpers as h from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator @@ -99,8 +98,8 @@ if request.GET.get('set'): request.GET.pop('set', None) if revision is None: - return redirect(url('changelog_home', repo_name=repo_name, **request.GET)) - return redirect(url('changelog_file_home', repo_name=repo_name, revision=revision, f_path=f_path, **request.GET)) + raise HTTPFound(location=url('changelog_home', repo_name=repo_name, **request.GET)) + raise HTTPFound(location=url('changelog_file_home', repo_name=repo_name, revision=revision, f_path=f_path, **request.GET)) limit = 2000 default = 100 @@ -118,7 +117,7 @@ branch_name not in c.db_repo_scm_instance.branches and branch_name not in c.db_repo_scm_instance.closed_branches and not revision): - return redirect(url('changelog_file_home', repo_name=c.repo_name, + raise HTTPFound(location=url('changelog_file_home', repo_name=c.repo_name, revision=branch_name, f_path=f_path or '')) if revision == 'tip': @@ -140,7 +139,7 @@ collection = cs.get_file_history(f_path) except RepositoryError as e: h.flash(safe_str(e), category='warning') - redirect(h.url('changelog_home', repo_name=repo_name)) + raise HTTPFound(location=h.url('changelog_home', repo_name=repo_name)) collection = list(reversed(collection)) else: collection = c.db_repo_scm_instance.get_changesets(start=0, end=revision, @@ -155,11 +154,11 @@ c.statuses = c.db_repo.statuses(page_revisions) except EmptyRepositoryError as e: h.flash(safe_str(e), category='warning') - return redirect(url('summary_home', repo_name=c.repo_name)) + raise HTTPFound(location=url('summary_home', repo_name=c.repo_name)) except (RepositoryError, ChangesetDoesNotExistError, Exception) as e: log.error(traceback.format_exc()) h.flash(safe_str(e), category='error') - return redirect(url('changelog_home', repo_name=c.repo_name)) + raise HTTPFound(location=url('changelog_home', repo_name=c.repo_name)) c.branch_name = branch_name c.branch_filters = [('', _('None'))] + \
--- a/kallithea/controllers/changeset.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/controllers/changeset.py Mon Oct 12 18:55:41 2015 +0200 @@ -29,13 +29,12 @@ import logging import traceback from collections import defaultdict -from webob.exc import HTTPForbidden, HTTPBadRequest, HTTPNotFound from pylons import tmpl_context as c, request, response from pylons.i18n.translation import _ -from pylons.controllers.util import redirect +from webob.exc import HTTPFound, HTTPForbidden, HTTPBadRequest, HTTPNotFound + from kallithea.lib.utils import jsonify - from kallithea.lib.vcs.exceptions import RepositoryError, \ ChangesetDoesNotExistError @@ -383,7 +382,7 @@ msg = _('Changing status on a changeset associated with ' 'a closed pull request is not allowed') h.flash(msg, category='warning') - return redirect(h.url('changeset_home', repo_name=repo_name, + raise HTTPFound(location=h.url('changeset_home', repo_name=repo_name, revision=revision)) action_logger(self.authuser, 'user_commented_revision:%s' % revision, @@ -392,7 +391,7 @@ Session().commit() if not request.environ.get('HTTP_X_PARTIAL_XHR'): - return redirect(h.url('changeset_home', repo_name=repo_name, + raise HTTPFound(location=h.url('changeset_home', repo_name=repo_name, revision=revision)) #only ajax below data = {
--- a/kallithea/controllers/compare.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/controllers/compare.py Mon Oct 12 18:55:41 2015 +0200 @@ -30,11 +30,11 @@ import logging import re -from webob.exc import HTTPBadRequest from pylons import request, tmpl_context as c, url -from pylons.controllers.util import redirect from pylons.i18n.translation import _ +from webob.exc import HTTPFound, HTTPBadRequest +from kallithea.lib.utils2 import safe_str from kallithea.lib.vcs.utils.hgcompat import unionrepo from kallithea.lib import helpers as h from kallithea.lib.base import BaseRepoController, render @@ -114,10 +114,10 @@ from dulwich.client import SubprocessGitClient gitrepo = Repo(org_repo.path) - SubprocessGitClient(thin_packs=False).fetch(other_repo.path, gitrepo) + SubprocessGitClient(thin_packs=False).fetch(safe_str(other_repo.path), gitrepo) gitrepo_remote = Repo(other_repo.path) - SubprocessGitClient(thin_packs=False).fetch(org_repo.path, gitrepo_remote) + SubprocessGitClient(thin_packs=False).fetch(safe_str(org_repo.path), gitrepo_remote) revs = [] for x in gitrepo_remote.get_walker(include=[other_rev], @@ -206,19 +206,19 @@ msg = 'Could not find org repo %s' % org_repo log.error(msg) h.flash(msg, category='error') - return redirect(url('compare_home', repo_name=c.repo_name)) + raise HTTPFound(location=url('compare_home', repo_name=c.repo_name)) if other_repo is None: msg = 'Could not find other repo %s' % other_repo log.error(msg) h.flash(msg, category='error') - return redirect(url('compare_home', repo_name=c.repo_name)) + raise HTTPFound(location=url('compare_home', repo_name=c.repo_name)) if org_repo.scm_instance.alias != other_repo.scm_instance.alias: msg = 'compare of two different kind of remote repos not available' log.error(msg) h.flash(msg, category='error') - return redirect(url('compare_home', repo_name=c.repo_name)) + raise HTTPFound(location=url('compare_home', repo_name=c.repo_name)) c.a_rev = self._get_ref_rev(org_repo, org_ref_type, org_ref_name, returnempty=True)
--- a/kallithea/controllers/files.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/controllers/files.py Mon Oct 12 18:55:41 2015 +0200 @@ -33,9 +33,9 @@ from pylons import request, response, tmpl_context as c, url from pylons.i18n.translation import _ -from pylons.controllers.util import redirect +from webob.exc import HTTPFound + from kallithea.lib.utils import jsonify, action_logger - from kallithea.lib import diffs from kallithea.lib import helpers as h @@ -306,7 +306,7 @@ % (h.person_by_id(repo.locked[0]), h.fmt_date(h.time_to_datetime(repo.locked[1]))), 'warning') - return redirect(h.url('files_home', + raise HTTPFound(location=h.url('files_home', repo_name=repo_name, revision='tip')) # check if revision is a branch identifier- basically we cannot @@ -316,7 +316,7 @@ if revision not in _branches.keys() + _branches.values(): h.flash(_('You can only delete files with revision ' 'being a valid branch '), category='warning') - return redirect(h.url('files_home', + raise HTTPFound(location=h.url('files_home', repo_name=repo_name, revision='tip', f_path=f_path)) @@ -352,7 +352,7 @@ except Exception: log.error(traceback.format_exc()) h.flash(_('Error occurred during commit'), category='error') - return redirect(url('changeset_home', + raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name, revision='tip')) return render('files/files_delete.html') @@ -366,7 +366,7 @@ % (h.person_by_id(repo.locked[0]), h.fmt_date(h.time_to_datetime(repo.locked[1]))), 'warning') - return redirect(h.url('files_home', + raise HTTPFound(location=h.url('files_home', repo_name=repo_name, revision='tip')) # check if revision is a branch identifier- basically we cannot @@ -376,7 +376,7 @@ if revision not in _branches.keys() + _branches.values(): h.flash(_('You can only edit files with revision ' 'being a valid branch '), category='warning') - return redirect(h.url('files_home', + raise HTTPFound(location=h.url('files_home', repo_name=repo_name, revision='tip', f_path=f_path)) @@ -386,7 +386,7 @@ c.file = self.__get_filenode(c.cs, f_path) if c.file.is_binary: - return redirect(url('files_home', repo_name=c.repo_name, + raise HTTPFound(location=url('files_home', repo_name=c.repo_name, revision=c.cs.raw_id, f_path=f_path)) c.default_message = _('Edited file %s via Kallithea') % (f_path) c.f_path = f_path @@ -405,7 +405,7 @@ if content == old_content: h.flash(_('No changes'), category='warning') - return redirect(url('changeset_home', repo_name=c.repo_name, + raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name, revision='tip')) try: self.scm_model.commit_change(repo=c.db_repo_scm_instance, @@ -418,7 +418,7 @@ except Exception: log.error(traceback.format_exc()) h.flash(_('Error occurred during commit'), category='error') - return redirect(url('changeset_home', + raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name, revision='tip')) return render('files/files_edit.html') @@ -433,7 +433,7 @@ % (h.person_by_id(repo.locked[0]), h.fmt_date(h.time_to_datetime(repo.locked[1]))), 'warning') - return redirect(h.url('files_home', + raise HTTPFound(location=h.url('files_home', repo_name=repo_name, revision='tip')) r_post = request.POST @@ -462,11 +462,11 @@ if not content: h.flash(_('No content'), category='warning') - return redirect(url('changeset_home', repo_name=c.repo_name, + raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name, revision='tip')) if not filename: h.flash(_('No filename'), category='warning') - return redirect(url('changeset_home', repo_name=c.repo_name, + raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name, revision='tip')) #strip all crap out of file, just leave the basename filename = os.path.basename(filename) @@ -492,14 +492,14 @@ except NonRelativePathError as e: h.flash(_('Location must be relative path and must not ' 'contain .. in path'), category='warning') - return redirect(url('changeset_home', repo_name=c.repo_name, + raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name, revision='tip')) except (NodeError, NodeAlreadyExistsError) as e: h.flash(_(e), category='error') except Exception: log.error(traceback.format_exc()) h.flash(_('Error occurred during commit'), category='error') - return redirect(url('changeset_home', + raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name, revision='tip')) return render('files/files_add.html') @@ -620,7 +620,7 @@ _url = url('files_home', repo_name=c.repo_name, revision=diff1, f_path=c.f_path) - return redirect(_url) + raise HTTPFound(location=_url) try: if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]: c.changeset_1 = c.db_repo_scm_instance.get_changeset(diff1) @@ -655,7 +655,7 @@ node2 = FileNode(f_path, '', changeset=c.changeset_2) except (RepositoryError, NodeError): log.error(traceback.format_exc()) - return redirect(url('files_home', repo_name=c.repo_name, + raise HTTPFound(location=url('files_home', repo_name=c.repo_name, f_path=f_path)) if c.action == 'download':
--- a/kallithea/controllers/forks.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/controllers/forks.py Mon Oct 12 18:55:41 2015 +0200 @@ -31,8 +31,8 @@ from formencode import htmlfill from pylons import tmpl_context as c, request, url -from pylons.controllers.util import redirect from pylons.i18n.translation import _ +from webob.exc import HTTPFound import kallithea.lib.helpers as h @@ -77,7 +77,7 @@ if c.repo_info is None: h.not_mapped_error(repo_name) - return redirect(url('repos')) + raise HTTPFound(location=url('repos')) c.default_user_id = User.get_default_user().user_id c.in_public_journal = UserFollowing.query()\ @@ -137,7 +137,7 @@ c.repo_info = Repository.get_by_repo_name(repo_name) if not c.repo_info: h.not_mapped_error(repo_name) - return redirect(url('home')) + raise HTTPFound(location=url('home')) defaults = self.__load_data(repo_name) @@ -186,6 +186,6 @@ h.flash(_('An error occurred during repository forking %s') % repo_name, category='error') - return redirect(h.url('repo_creating_home', + raise HTTPFound(location=h.url('repo_creating_home', repo_name=form_result['repo_name_full'], task_id=task_id))
--- a/kallithea/controllers/login.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/controllers/login.py Mon Oct 12 18:55:41 2015 +0200 @@ -31,10 +31,9 @@ import formencode from formencode import htmlfill +from pylons.i18n.translation import _ +from pylons import request, session, tmpl_context as c, url from webob.exc import HTTPFound, HTTPBadRequest -from pylons.i18n.translation import _ -from pylons.controllers.util import redirect -from pylons import request, session, tmpl_context as c, url import kallithea.lib.helpers as h from kallithea.lib.auth import AuthUser, HasPermissionAnyDecorator @@ -79,11 +78,10 @@ else: c.came_from = url('home') - not_default = self.authuser.username != User.DEFAULT_USER ip_allowed = AuthUser.check_ip_allowed(self.authuser, self.ip_addr) # redirect if already logged in - if self.authuser.is_authenticated and not_default and ip_allowed: + if self.authuser.is_authenticated and ip_allowed: raise HTTPFound(location=c.came_from) if request.POST: @@ -152,7 +150,7 @@ h.flash(_('You have successfully registered into Kallithea'), category='success') Session().commit() - return redirect(url('login_home')) + raise HTTPFound(location=url('login_home')) except formencode.Invalid as errors: return htmlfill.render( @@ -196,7 +194,7 @@ redirect_link = UserModel().send_reset_password_email(form_result) h.flash(_('A password reset confirmation code has been sent'), category='success') - return redirect(redirect_link) + raise HTTPFound(location=redirect_link) except formencode.Invalid as errors: return htmlfill.render( @@ -249,12 +247,12 @@ UserModel().reset_password(form_result['email'], form_result['password']) h.flash(_('Successfully updated password'), category='success') - return redirect(url('login_home')) + raise HTTPFound(location=url('login_home')) def logout(self): session.delete() log.info('Logging out and deleting session for user') - redirect(url('home')) + raise HTTPFound(location=url('home')) def authentication_token(self): """Return the CSRF protection token for the session - just like it
--- a/kallithea/controllers/pullrequests.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/controllers/pullrequests.py Mon Oct 12 18:55:41 2015 +0200 @@ -30,11 +30,9 @@ import formencode import re -from webob.exc import HTTPNotFound, HTTPForbidden, HTTPBadRequest - from pylons import request, tmpl_context as c, url -from pylons.controllers.util import redirect from pylons.i18n.translation import _ +from webob.exc import HTTPFound, HTTPNotFound, HTTPForbidden, HTTPBadRequest from kallithea.lib.vcs.utils.hgcompat import unionrepo from kallithea.lib.compat import json @@ -237,7 +235,7 @@ except EmptyRepositoryError as e: h.flash(h.literal(_('There are no changesets yet')), category='warning') - redirect(url('summary_home', repo_name=org_repo.repo_name)) + raise HTTPFound(location=url('summary_home', repo_name=org_repo.repo_name)) org_rev = request.GET.get('rev_end') # rev_start is not directly useful - its parent could however be used @@ -369,9 +367,9 @@ h.flash(_('Error occurred while creating pull request'), category='error') log.error(traceback.format_exc()) - return redirect(url('pullrequest_home', repo_name=repo_name)) + raise HTTPFound(location=url('pullrequest_home', repo_name=repo_name)) - return redirect(pull_request.url()) + raise HTTPFound(location=pull_request.url()) def create_update(self, old_pull_request, updaterev, title, description, reviewers_ids): org_repo = RepoModel()._get_repo(old_pull_request.org_repo.repo_name) @@ -456,7 +454,7 @@ h.flash(_('Error occurred while creating pull request'), category='error') log.error(traceback.format_exc()) - return redirect(old_pull_request.url()) + raise HTTPFound(location=old_pull_request.url()) ChangesetCommentsModel().create( text=_('Closed, replaced by %s .') % pull_request.url(canonical=True), @@ -470,7 +468,7 @@ h.flash(_('Pull request update created'), category='success') - return redirect(pull_request.url()) + raise HTTPFound(location=pull_request.url()) # pullrequest_post for PR editing @LoginRequired() @@ -513,7 +511,7 @@ Session().commit() h.flash(_('Pull request updated'), category='success') - return redirect(pull_request.url()) + raise HTTPFound(location=pull_request.url()) @LoginRequired() @NotAnonymous() @@ -528,7 +526,7 @@ Session().commit() h.flash(_('Successfully deleted pull request'), category='success') - return redirect(url('my_pullrequests')) + raise HTTPFound(location=url('my_pullrequests')) raise HTTPForbidden() @LoginRequired() @@ -762,7 +760,7 @@ Session().commit() if not request.environ.get('HTTP_X_PARTIAL_XHR'): - return redirect(pull_request.url()) + raise HTTPFound(location=pull_request.url()) data = { 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
--- a/kallithea/controllers/summary.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/controllers/summary.py Mon Oct 12 18:55:41 2015 +0200 @@ -114,8 +114,9 @@ def index(self, repo_name): _load_changelog_summary() - username = '' - if self.authuser.username != User.DEFAULT_USER: + if self.authuser.is_default_user: + username = '' + else: username = safe_str(self.authuser.username) _def_clone_uri = _def_clone_uri_by_id = c.clone_uri_tmpl
--- a/kallithea/i18n/de/LC_MESSAGES/kallithea.po Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/i18n/de/LC_MESSAGES/kallithea.po Mon Oct 12 18:55:41 2015 +0200 @@ -11,7 +11,7 @@ "PO-Revision-Date: 2015-09-08 10:56+0200\n" "Last-Translator: Robert Rauch <mail@robertrauch.de>\n" "Language-Team: German " -"<https://hosted.weblate.org/projects/kallithea/stable/de/>\n" +"<https://hosted.weblate.org/projects/kallithea/kallithea/de/>\n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n"
--- a/kallithea/lib/auth.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/lib/auth.py Mon Oct 12 18:55:41 2015 +0200 @@ -35,12 +35,12 @@ from decorator import decorator from pylons import url, request, session -from pylons.controllers.util import abort, redirect from pylons.i18n.translation import _ from webhelpers.pylonslib import secure_form from sqlalchemy import or_ from sqlalchemy.orm.exc import ObjectDeletedError from sqlalchemy.orm import joinedload +from webob.exc import HTTPFound, HTTPBadRequest, HTTPForbidden, HTTPMethodNotAllowed from kallithea import __platform__, is_windows, is_unix from kallithea.lib.vcs.utils.lazy import LazyProperty @@ -465,8 +465,7 @@ access to Kallithea is enabled, the default user is loaded instead. `AuthUser` does not by itself authenticate users and the constructor - sets the `is_authenticated` field to False, except when falling back - to the default anonymous user (if enabled). It's up to other parts + sets the `is_authenticated` field to False. It's up to other parts of the code to check e.g. if a supplied password is correct, and if so, set `is_authenticated` to True. @@ -508,9 +507,7 @@ if not is_user_loaded: is_user_loaded = self._fill_data(self.anonymous_user) - # The anonymous user is always "logged in". - if self.user_id == self.anonymous_user.user_id: - self.is_authenticated = True + self.is_default_user = (self.user_id == self.anonymous_user.user_id) if not self.username: self.username = 'None' @@ -623,17 +620,12 @@ def __repr__(self): return "<AuthUser('id:%s[%s] auth:%s')>"\ - % (self.user_id, self.username, self.is_authenticated) - - def set_authenticated(self, authenticated=True): - if self.user_id != self.anonymous_user.user_id: - self.is_authenticated = authenticated + % (self.user_id, self.username, (self.is_authenticated or self.is_default_user)) def to_cookie(self): """ Serializes this login session to a cookie `dict`. """ return { 'user_id': self.user_id, - 'is_authenticated': self.is_authenticated, 'is_external_auth': self.is_external_auth, } @@ -647,9 +639,7 @@ user_id=cookie.get('user_id'), is_external_auth=cookie.get('is_external_auth', False), ) - if not au.is_authenticated and au.user_id is not None: - # user is not authenticated and not empty - au.set_authenticated(cookie.get('is_authenticated')) + au.is_authenticated = True return au @classmethod @@ -716,7 +706,7 @@ if message: h.flash(h.literal(message), category='warning') log.debug('Redirecting to login page, origin: %s', p) - return redirect(url('login_home', came_from=p)) + raise HTTPFound(location=url('login_home', came_from=p)) class LoginRequired(object): @@ -758,13 +748,13 @@ else: # controller does not allow API access log.warning('API access to %s is not allowed', loc) - return abort(403) + raise HTTPForbidden() # Only allow the following HTTP request methods. (We sometimes use POST # requests with a '_method' set to 'PUT' or 'DELETE'; but that is only # used for the route lookup, and does not affect request.method.) if request.method not in ['GET', 'HEAD', 'POST', 'PUT']: - return abort(405) + raise HTTPMethodNotAllowed() # Make sure CSRF token never appears in the URL. If so, invalidate it. if secure_form.token_key in request.GET: @@ -785,17 +775,17 @@ token = request.POST.get(secure_form.token_key) if not token or token != secure_form.authentication_token(): log.error('CSRF check failed') - return abort(403) + raise HTTPForbidden() # WebOb already ignores request payload parameters for anything other # than POST/PUT, but double-check since other Kallithea code relies on # this assumption. if request.method not in ['POST', 'PUT'] and request.POST: log.error('%r request with payload parameters; WebOb should have stopped this', request.method) - return abort(400) + raise HTTPBadRequest() # regular user authentication - if user.is_authenticated: + if user.is_authenticated or user.is_default_user: log.info('user %s authenticated with regular auth @ %s', user, loc) return func(*fargs, **fkwargs) else: @@ -816,9 +806,7 @@ log.debug('Checking if user is not anonymous @%s', cls) - anonymous = self.user.username == User.DEFAULT_USER - - if anonymous: + if self.user.is_default_user: return redirect_to_login(_('You need to be a registered user to ' 'perform this action')) else: @@ -848,13 +836,10 @@ else: log.debug('Permission denied for %s %s', cls, self.user) - anonymous = self.user.username == User.DEFAULT_USER - - if anonymous: + if self.user.is_default_user: return redirect_to_login(_('You need to be signed in to view this page')) else: - # redirect with forbidden ret code - return abort(403) + raise HTTPForbidden() def check_permissions(self): """Dummy function for overriding"""
--- a/kallithea/lib/base.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/lib/base.py Mon Oct 12 18:55:41 2015 +0200 @@ -40,7 +40,6 @@ from pylons import config, tmpl_context as c, request, session, url from pylons.controllers import WSGIController -from pylons.controllers.util import redirect from pylons.templating import render_mako as render # don't remove this import from pylons.i18n.translation import _ @@ -117,7 +116,9 @@ auth_user = AuthUser(dbuser=user, is_external_auth=is_external_auth) - auth_user.set_authenticated() + # It should not be possible to explicitly log in as the default user. + assert not auth_user.is_default_user + auth_user.is_authenticated = True # Start new session to prevent session fixation attacks. session.invalidate() @@ -392,7 +393,9 @@ # Authenticate by session cookie # In ancient login sessions, 'authuser' may not be a dict. # In that case, the user will have to log in again. - if isinstance(session_authuser, dict): + # v0.3 and earlier included an 'is_authenticated' key; if present, + # this must be True. + if isinstance(session_authuser, dict) and session_authuser.get('is_authenticated', True): try: return AuthUser.from_cookie(session_authuser) except UserCreationError as e: @@ -479,7 +482,7 @@ if route in ['repo_creating_home']: return check_url = url('repo_creating_home', repo_name=c.repo_name) - return redirect(check_url) + raise webob.exc.HTTPFound(location=check_url) dbr = c.db_repo = _dbr c.db_repo_scm_instance = c.db_repo.scm_instance
--- a/kallithea/model/comment.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/model/comment.py Mon Oct 12 18:55:41 2015 +0200 @@ -266,10 +266,10 @@ q = q.filter(ChangesetComment.line_no == None)\ .filter(ChangesetComment.f_path == None) - if revision: + if revision is not None: q = q.filter(ChangesetComment.revision == revision)\ .filter(ChangesetComment.repo_id == repo_id) - elif pull_request: + elif pull_request is not None: pull_request = self.__get_pull_request(pull_request) q = q.filter(ChangesetComment.pull_request == pull_request) else:
--- a/kallithea/model/db.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/model/db.py Mon Oct 12 18:55:41 2015 +0200 @@ -2103,7 +2103,7 @@ return "%s%s" % (prefix, key) @classmethod - def set_invalidate(cls, repo_name, delete=False): + def set_invalidate(cls, repo_name): """ Mark all caches of a repo as invalid in the database. """ @@ -2114,11 +2114,7 @@ for inv_obj in inv_objs: log.debug('marking %s key for invalidation based on repo_name=%s', inv_obj, safe_str(repo_name)) - if delete: - Session().delete(inv_obj) - else: - inv_obj.cache_active = False - Session().add(inv_obj) + Session().delete(inv_obj) Session().commit() @classmethod @@ -2416,11 +2412,15 @@ notification.type_ = type_ notification.created_on = datetime.datetime.now() - for u in recipients: - assoc = UserNotification() - assoc.notification = notification - assoc.user_id = u.user_id - Session().add(assoc) + for recipient in recipients: + un = UserNotification() + un.notification = notification + un.user_id = recipient.user_id + # Mark notifications to self "pre-read" - should perhaps just be skipped + if recipient == created_by: + un.read = True + Session().add(un) + Session().add(notification) Session().flush() # assign notificaiton.notification_id return notification
--- a/kallithea/model/scm.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/model/scm.py Mon Oct 12 18:55:41 2015 +0200 @@ -331,13 +331,13 @@ .filter(RepoGroup.group_parent_id == None).all() return [x for x in RepoGroupList(all_groups)] - def mark_for_invalidation(self, repo_name, delete=False): + def mark_for_invalidation(self, repo_name): """ Mark caches of this repo invalid in the database. :param repo_name: the repo for which caches should be marked invalid """ - CacheInvalidation.set_invalidate(repo_name, delete=delete) + CacheInvalidation.set_invalidate(repo_name) repo = Repository.get_by_repo_name(repo_name) if repo is not None: repo.update_changeset_cache()
--- a/kallithea/public/css/style.css Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/public/css/style.css Mon Oct 12 18:55:41 2015 +0200 @@ -4346,9 +4346,6 @@ color: #666; font-size: 16px; } -.inline-comments-button .add-comment { - margin: 2px 0px 8px 5px !important -} input.status_change_radio { margin: 2px 0 5px 15px; @@ -4557,6 +4554,19 @@ overflow: hidden; } +.compare-revision-selector { + font-weight: bold; + font-size: 14px; +} +.compare-revision-selector > div { + display: inline-block; + margin-left: 8px; + vertical-align: middle; +} +.compare-revision-selector .btn { + margin-bottom: 0; +} + div.diffblock { overflow: auto; @@ -4572,6 +4582,7 @@ div.diffblock.margined { margin: 0px 20px 0px 20px; } +.compare-revision-selector, div.diffblock .code-header { border-bottom: 1px solid #CCCCCC; background: #EEEEEE;
--- a/kallithea/public/js/base.js Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/public/js/base.js Mon Oct 12 18:55:41 2015 +0200 @@ -377,15 +377,16 @@ ; }; -var ajaxGET = function(url,success) { +var ajaxGET = function(url, success, failure) { + if(failure === undefined) { + failure = function(jqXHR, textStatus, errorThrown) { + if (textStatus != "abort") + alert("Ajax GET error: " + textStatus); + }; + } return $.ajax({url: url, headers: {'X-PARTIAL-XHR': '1'}, cache: false}) .done(success) - .fail(function(jqXHR, textStatus, errorThrown) { - if (textStatus == "abort") - return; - alert("Ajax GET error: " + textStatus); - }) - ; + .fail(failure); }; var ajaxPOST = function(url, postData, success, failure) {
--- a/kallithea/templates/admin/repos/repo_edit_caches.html Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/templates/admin/repos/repo_edit_caches.html Mon Oct 12 18:55:41 2015 +0200 @@ -1,7 +1,7 @@ ${h.form(url('edit_repo_caches', repo_name=c.repo_name), method='put')} <div class="form"> <div class="fields"> - ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate Repository Cache'),class_="btn btn-small",onclick="return confirm('"+_('Confirm to invalidate repository cache.')+"');")} + ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate Repository Cache'),class_="btn btn-small")} <div class="field" style="border:none;color:#888"> <ul> <li>${_('Manually invalidate cache for this repository. On first access, the repository will be cached again.')}
--- a/kallithea/templates/changeset/changeset.html Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/templates/changeset/changeset.html Mon Oct 12 18:55:41 2015 +0200 @@ -217,10 +217,8 @@ var boxid = $(target).attr('id_for'); if(target.checked){ $('#{0} .inline-comments'.format(boxid)).show(); - $('#{0} .inline-comments-button'.format(boxid)).show(); }else{ $('#{0} .inline-comments'.format(boxid)).hide(); - $('#{0} .inline-comments-button'.format(boxid)).hide(); } });
--- a/kallithea/templates/changeset/diff_block.html Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/templates/changeset/diff_block.html Mon Oct 12 18:55:41 2015 +0200 @@ -77,19 +77,19 @@ ## TODO: link to ancestor and head of other instead of exactly other %if op == 'A': ${_('Added')} - <a class="spantag" href="${h.url('files_home', repo_name=c.cs_repo.repo_name, f_path=filenode_path, revision=c.cs_rev)}">${h.short_id(c.cs_ref_name) if c.cs_ref_type=='rev' else c.cs_ref_name}</a> + <a class="spantag" href="${h.url('files_home', repo_name=c.cs_repo.repo_name, f_path=filenode_path, revision=c.cs_rev)}">${h.short_ref(c.cs_ref_type, c.cs_ref_name)}</a> %elif op == 'M': - <a class="spantag" href="${h.url('files_home', repo_name=c.a_repo.repo_name, f_path=filenode_path, revision=c.a_rev)}">${h.short_id(c.a_ref_name) if c.a_ref_type=='rev' else c.a_ref_name}</a> + <a class="spantag" href="${h.url('files_home', repo_name=c.a_repo.repo_name, f_path=filenode_path, revision=c.a_rev)}">${h.short_ref(c.a_ref_type, c.a_ref_name)}</a> <i class="icon-right"></i> - <a class="spantag" href="${h.url('files_home', repo_name=c.cs_repo.repo_name, f_path=filenode_path, revision=c.cs_rev)}">${h.short_id(c.cs_ref_name) if c.cs_ref_type=='rev' else c.cs_ref_name}</a> + <a class="spantag" href="${h.url('files_home', repo_name=c.cs_repo.repo_name, f_path=filenode_path, revision=c.cs_rev)}">${h.short_ref(c.cs_ref_type, c.cs_ref_name)}</a> %elif op == 'D': ${_('Deleted')} - <a class="spantag" href="${h.url('files_home', repo_name=c.a_repo.repo_name, f_path=filenode_path, revision=c.a_rev)}">${h.short_id(c.a_ref_name) if c.a_ref_type=='rev' else c.a_ref_name}</a> + <a class="spantag" href="${h.url('files_home', repo_name=c.a_repo.repo_name, f_path=filenode_path, revision=c.a_rev)}">${h.short_ref(c.a_ref_type, c.a_ref_name)}</a> %elif op == 'R': ${_('Renamed')} - <a class="spantag" href="${h.url('files_home', repo_name=c.a_repo.repo_name, f_path=filenode_path, revision=c.a_rev)}">${h.short_id(c.a_ref_name) if c.a_ref_type=='rev' else c.a_ref_name}</a> + <a class="spantag" href="${h.url('files_home', repo_name=c.a_repo.repo_name, f_path=filenode_path, revision=c.a_rev)}">${h.short_ref(c.a_ref_type, c.a_ref_name)}</a> <i class="icon-right"></i> - <a class="spantag" href="${h.url('files_home', repo_name=c.cs_repo.repo_name, f_path=filenode_path, revision=c.cs_rev)}">${h.short_id(c.cs_ref_name) if c.cs_ref_type=='rev' else c.cs_ref_name}</a> + <a class="spantag" href="${h.url('files_home', repo_name=c.cs_repo.repo_name, f_path=filenode_path, revision=c.cs_rev)}">${h.short_ref(c.cs_ref_type, c.cs_ref_name)}</a> %else: ${op}??? %endif
--- a/kallithea/templates/compare/compare_diff.html Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/templates/compare/compare_diff.html Mon Oct 12 18:55:41 2015 +0200 @@ -26,9 +26,15 @@ </div> <div class="table"> <div id="body" class="diffblock"> - <div class="code-header"> + <div class="compare-revision-selector"> + ## divs are "inline-block" and cannot have whitespace between them. <div> - ${h.hidden('compare_org')} <i class="icon-right"></i> ${h.hidden('compare_other')} + ${h.hidden('compare_org')} + </div><div> + <i class="icon-right"></i> + </div><div> + ${h.hidden('compare_other')} + </div><div> %if not c.compare_home: <a class="btn btn-small" href="${c.swap_url}"><i class="icon-arrows-cw"></i> ${_('Swap')}</a> %endif
--- a/kallithea/tests/__init__.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/tests/__init__.py Mon Oct 12 18:55:41 2015 +0200 @@ -220,7 +220,6 @@ user = user and User.get(user) user = user and user.username self.assertEqual(user, expected_username) - self.assertEqual(cookie.get('is_authenticated'), True) def authentication_token(self): return self.app.get(url('authentication_token')).body
--- a/kallithea/tests/models/test_notifications.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/tests/models/test_notifications.py Mon Oct 12 18:55:41 2015 +0200 @@ -144,7 +144,7 @@ Session().commit() self.assertEqual(NotificationModel() - .get_unread_cnt_for_user(self.u1), 1) + .get_unread_cnt_for_user(self.u1), 0) self.assertEqual(NotificationModel() .get_unread_cnt_for_user(self.u2), 0) self.assertEqual(NotificationModel() @@ -156,7 +156,7 @@ Session().commit() self.assertEqual(NotificationModel() - .get_unread_cnt_for_user(self.u1), 2) + .get_unread_cnt_for_user(self.u1), 0) self.assertEqual(NotificationModel() .get_unread_cnt_for_user(self.u2), 1) self.assertEqual(NotificationModel()
--- a/kallithea/tests/other/manual_test_vcs_operations.py Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/tests/other/manual_test_vcs_operations.py Mon Oct 12 18:55:41 2015 +0200 @@ -273,8 +273,8 @@ stdout, stderr = _add_files_and_push('hg', DEST, files_no=1) key = CacheInvalidation.query().filter(CacheInvalidation.cache_key - ==HG_REPO).one() - self.assertEqual(key.cache_active, False) + ==HG_REPO).all() + self.assertEqual(key, []) def test_push_invalidates_cache_git(self): key = CacheInvalidation.query().filter(CacheInvalidation.cache_key @@ -295,9 +295,8 @@ _check_proper_git_push(stdout, stderr) key = CacheInvalidation.query().filter(CacheInvalidation.cache_key - ==GIT_REPO).one() - print CacheInvalidation.get_all() - self.assertEqual(key.cache_active, False) + ==GIT_REPO).all() + self.assertEqual(key, []) def test_push_wrong_credentials_hg(self): DEST = _get_tmp_dir()
--- a/kallithea/tests/test.ini Sun Oct 11 22:09:42 2015 +0200 +++ b/kallithea/tests/test.ini Mon Oct 12 18:55:41 2015 +0200 @@ -163,6 +163,7 @@ ## COMMON ## host = 127.0.0.1 +#port = 5000 port = 4999 ## middleware for hosting the WSGI application under a URL prefix @@ -224,6 +225,7 @@ ## options for showing and identifying changesets show_sha_length = 12 +#show_revision_number = false show_revision_number = true ## gist URL alias, used to create nicer urls for gist. This should be an @@ -280,12 +282,6 @@ #issue_server_link_wiki = https://wiki.example.com/{id} #issue_prefix_wiki = WIKI- -## instance-id prefix -## a prefix key for this instance used for cache invalidation when running -## multiple instances of kallithea, make sure it's globally unique for -## all running kallithea instances. Leave empty if you don't use it -instance_id = - ## alternative return HTTP header for failed authentication. Default HTTP ## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with ## handling that. Set this variable to 403 to return HTTPForbidden @@ -347,6 +343,7 @@ beaker.cache.long_term.key_length = 256 beaker.cache.sql_cache_short.type = memory +#beaker.cache.sql_cache_short.expire = 10 beaker.cache.sql_cache_short.expire = 1 beaker.cache.sql_cache_short.key_length = 256 @@ -543,8 +540,8 @@ [logger_sqlalchemy] #level = INFO +level = ERROR #handlers = console_sql -level = ERROR handlers = console qualname = sqlalchemy.engine propagate = 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/docs-headings.py Mon Oct 12 18:55:41 2015 +0200 @@ -0,0 +1,66 @@ +#!/usr/bin/env python2 + +""" +Consistent formatting of rst section titles +""" + +import re +import subprocess + +spaces = [ + (0, 1), # we assume this is a over-and-underlined header + (2, 1), + (1, 1), + (1, 0), + (1, 0), + ] + +# match on a header line underlined with one of the valid characters +headermatch = re.compile(r'''\n*(.+)\n([][!"#$%&'()*+,./:;<=>?@\\^_`{|}~-])\2{2,}\n+''', flags=re.MULTILINE) + + +def main(): + for fn in subprocess.check_output(['hg', 'loc', 'set:**.rst+kallithea/i18n/how_to']).splitlines(): + print 'processing %s:' % fn + s = file(fn).read() + + # find levels and their styles + lastpos = 0 + styles = [] + for markup in headermatch.findall(s): + style = markup[1] + if style in styles: + stylepos = styles.index(style) + if stylepos > lastpos + 1: + print 'bad style %r with level %s - was at %s' % (style, stylepos, lastpos) + else: + stylepos = len(styles) + if stylepos > lastpos + 1: + print 'bad new style %r - expected %r' % (style, styles[lastpos + 1]) + else: + styles.append(style) + lastpos = stylepos + + # remove superfluous spacing (may however be restored by header spacing) + s = re.sub(r'''(\n\n)\n*''', r'\1', s, flags=re.MULTILINE) + + # rewrite header markup with correct style, length and spacing + def subf(m): + title, style = m.groups() + level = styles.index(style) + before, after = spaces[level] + return '\n' * (before + 1) + title + '\n' + style * len(title) + '\n' * (after + 1) + s = headermatch.sub(subf, s) + + # remove superfluous spacing when headers are adjacent + s = re.sub(r'''(\n.+\n([][!"#$%&'()*+,./:;<=>?@\\^_`{|}~-])\2{2,}\n\n\n)\n*''', r'\1', s, flags=re.MULTILINE) + # fix trailing space and spacing before link sections + s = s.strip() + '\n' + s = re.sub(r'''\n+((?:\.\. _[^\n]*\n)+)$''', r'\n\n\n\1', s) + + file(fn, 'w').write(s) + print subprocess.check_output(['hg', 'diff', fn]) + print + +if __name__ == '__main__': + main()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/generate-ini.py Mon Oct 12 18:55:41 2015 +0200 @@ -0,0 +1,173 @@ +#!/usr/bin/env python2 +""" +Based on kallithea/bin/template.ini.mako, generate + kallithea/config/deployment.ini_tmpl + development.ini + kallithea/tests/test.ini +""" + +import re + +makofile = 'kallithea/bin/template.ini.mako' + +# the mako conditionals used in all other ini files and templates +selected_mako_conditionals = set([ + "database_engine == 'sqlite'", + "http_server == 'waitress'", + "error_aggregation_service == 'errormator'", + "error_aggregation_service == 'sentry'", +]) + +# the mako variables used in all other ini files and templates +mako_variable_values = { + 'host': '127.0.0.1', + 'port': '5000', + 'here': '%(here)s', + 'uuid()': '${app_instance_uuid}', +} + +# files to be generated from the mako template +ini_files = [ + ('kallithea/config/deployment.ini_tmpl', + ''' + Kallithea - Example config + + The %(here)s variable will be replaced with the parent directory of this file + ''', + {}, # exactly the same settings as template.ini.mako + ), + ('kallithea/tests/test.ini', + ''' + Kallithea - config for tests: + initial_repo_scan = true + vcs_full_cache = false + sqlalchemy and kallithea_test.sqlite + custom logging + + The %(here)s variable will be replaced with the parent directory of this file + ''', + { + '[server:main]': { + 'port': '4999', + }, + '[app:main]': { + 'initial_repo_scan': 'true', + 'app_instance_uuid': 'test', + 'vcs_full_cache': 'false', + 'show_revision_number': 'true', + 'beaker.cache.sql_cache_short.expire': '1', + 'beaker.session.secret': '{74e0cd75-b339-478b-b129-07dd221def1f}', + 'sqlalchemy.db1.url': 'sqlite:///%(here)s/kallithea_test.sqlite', + }, + '[logger_root]': { + 'level': 'DEBUG', + }, + '[logger_sqlalchemy]': { + 'level': 'ERROR', + 'handlers': 'console', + }, + '[handler_console]': { + 'level': 'NOTSET', + }, + }, + ), + ('development.ini', + ''' + Kallithea - Development config: + listening on *:5000 + sqlite and kallithea.db + initial_repo_scan = true + set debug = true + verbose and colorful logging + + The %(here)s variable will be replaced with the parent directory of this file + ''', + { + '[server:main]': { + 'host': '0.0.0.0', + }, + '[app:main]': { + 'initial_repo_scan': 'true', + 'set debug': 'true', + 'app_instance_uuid': 'development-not-secret', + 'beaker.session.secret': 'development-not-secret', + }, + '[handler_console]': { + 'level': 'DEBUG', + 'formatter': 'color_formatter', + }, + '[handler_console_sql]': { + 'level': 'DEBUG', + 'formatter': 'color_formatter_sql', + }, + }, + ), +] + + +def main(): + # make sure all mako lines starting with '#' (the '##' comments) are marked up as <text> + print 'reading:', makofile + mako_org = file(makofile).read() + mako_no_text_markup = re.sub(r'</?%text>', '', mako_org) + mako_marked_up = re.sub(r'\n(##.*)', r'\n<%text>\1</%text>', mako_no_text_markup, flags=re.MULTILINE) + if mako_marked_up != mako_org: + print 'writing:', makofile + file(makofile, 'w').write(mako_marked_up) + + # select the right mako conditionals for the other less sophisticated formats + def sub_conditionals(m): + """given a %if...%endif match, replace with just the selected + conditional sections enabled and the rest as comments + """ + conditional_lines = m.group(1) + def sub_conditional(m): + """given a conditional and the corresponding lines, return them raw + or commented out, based on whether conditional is selected + """ + criteria, lines = m.groups() + if criteria not in selected_mako_conditionals: + lines = '\n'.join((l if not l or l.startswith('#') else '#' + l) for l in lines.split('\n')) + return lines + conditional_lines = re.sub(r'^%(?:el)?if (.*):\n((?:^[^%\n].*\n|\n)*)', + sub_conditional, conditional_lines, flags=re.MULTILINE) + return conditional_lines + mako_no_conditionals = re.sub(r'^(%if .*\n(?:[^%\n].*\n|%elif .*\n|\n)*)%endif\n', + sub_conditionals, mako_no_text_markup, flags=re.MULTILINE) + + # expand mako variables + def pyrepl(m): + return mako_variable_values.get(m.group(1), m.group(0)) + mako_no_variables = re.sub(r'\${([^}]*)}', pyrepl, mako_no_conditionals) + + # remove utf-8 coding header + base_ini = re.sub(r'^## -\*- coding: utf-8 -\*-\n', '', mako_no_variables) + + # create ini files + for fn, desc, settings in ini_files: + print 'updating:', fn + ini_lines = re.sub( + '# Kallithea - config file generated with kallithea-config *#\n', + ''.join('# %-77s#\n' % l.strip() for l in desc.strip().split('\n')), + base_ini) + def process_section(m): + """process a ini section, replacing values as necessary""" + sectionname, lines = m.groups() + if sectionname in settings: + section_settings = settings[sectionname] + def process_line(m): + """process a section line and update value if necessary""" + setting, value = m.groups() + line = m.group(0) + if setting in section_settings: + line = '%s = %s' % (setting, section_settings[setting]) + if '$' not in value: + line = '#%s = %s\n%s' % (setting, value, line) + return line.rstrip() + lines = re.sub(r'^([^#\n].*) = ?(.*)', process_line, lines, flags=re.MULTILINE) + return sectionname + '\n' + lines + ini_lines = re.sub(r'^(\[.*\])\n((?:(?:[^[\n].*)?\n)*)', process_section, ini_lines, flags=re.MULTILINE) + file(fn, 'w').write(ini_lines) + +if __name__ == '__main__': + main()