Changeset - 642847355a10
[Not reviewed]
default
0 8 0
Mads Kiilerich - 7 years ago 2019-01-23 03:52:13
mads@kiilerich.com
Grafted from: 4efe37046a51
hooks: make sure push and pull hooks always are enabled

Don't put things in the database when we pretty much assume they always have
exact content, without any reasonable use case for customization.
8 files changed with 7 insertions and 33 deletions:
0 comments (0 inline, 0 general)
kallithea/controllers/admin/settings.py
Show inline comments
 
@@ -88,54 +88,48 @@ class SettingsController(BaseController)
 
            application_form = ApplicationUiSettingsForm()()
 
            try:
 
                form_result = application_form.to_python(dict(request.POST))
 
            except formencode.Invalid as errors:
 
                return htmlfill.render(
 
                     render('admin/settings/settings.html'),
 
                     defaults=errors.value,
 
                     errors=errors.error_dict or {},
 
                     prefix_error=False,
 
                     encoding="UTF-8",
 
                     force_defaults=False)
 

	
 
            try:
 
                if c.visual.allow_repo_location_change:
 
                    sett = Ui.get_by_key('paths', '/')
 
                    sett.ui_value = form_result['paths_root_path']
 

	
 
                # HOOKS
 
                sett = Ui.get_by_key('hooks', Ui.HOOK_UPDATE)
 
                sett.ui_active = form_result['hooks_changegroup_update']
 

	
 
                sett = Ui.get_by_key('hooks', Ui.HOOK_REPO_SIZE)
 
                sett.ui_active = form_result['hooks_changegroup_repo_size']
 

	
 
                sett = Ui.get_by_key('hooks', Ui.HOOK_PUSH_LOG)
 
                sett.ui_active = form_result['hooks_changegroup_push_logger']
 

	
 
                sett = Ui.get_by_key('hooks', Ui.HOOK_PULL_LOG)
 
                sett.ui_active = form_result['hooks_outgoing_pull_logger']
 

	
 
                ## EXTENSIONS
 
                sett = Ui.get_or_create('extensions', 'largefiles')
 
                sett.ui_active = form_result['extensions_largefiles']
 

	
 
                sett = Ui.get_or_create('extensions', 'hgsubversion')
 
                sett.ui_active = form_result['extensions_hgsubversion']
 
                if sett.ui_active:
 
                    try:
 
                        import hgsubversion  # pragma: no cover
 
                    except ImportError:
 
                        raise HgsubversionImportError
 

	
 
#                sett = Ui.get_or_create('extensions', 'hggit')
 
#                sett.ui_active = form_result['extensions_hggit']
 

	
 
                Session().commit()
 

	
 
                h.flash(_('Updated VCS settings'), category='success')
 

	
 
            except HgsubversionImportError:
 
                log.error(traceback.format_exc())
 
                h.flash(_('Unable to activate hgsubversion support. '
 
                          'The "hgsubversion" library is missing'),
 
                        category='error')
kallithea/lib/db_manage.py
Show inline comments
 
@@ -331,50 +331,48 @@ class DbManage(object):
 
        if retries == 0:
 
            sys.exit('max retries reached')
 
        if not path_ok:
 
            if _path is not None:
 
                sys.exit('Invalid repo path: %s' % _path)
 
            retries -= 1
 
            return self.config_prompt(test_repo_path, retries) # recursing!!!
 

	
 
        real_path = os.path.normpath(os.path.realpath(path))
 

	
 
        if real_path != os.path.normpath(path):
 
            log.warning('Using normalized path %s instead of %s', real_path, path)
 

	
 
        return real_path
 

	
 
    def create_settings(self, path):
 

	
 
        ui_config = [
 
            ('web', 'allow_archive', 'gz zip bz2', True),
 
            ('web', 'baseurl', '/', True),
 
            ('paths', '/', path, True),
 
            #('phases', 'publish', 'false', False)
 
            ('hooks', Ui.HOOK_UPDATE, 'hg update >&2', False),
 
            ('hooks', Ui.HOOK_REPO_SIZE, 'python:kallithea.lib.hooks.repo_size', True),
 
            ('hooks', Ui.HOOK_PUSH_LOG, 'python:kallithea.lib.hooks.log_push_action', True),
 
            ('hooks', Ui.HOOK_PULL_LOG, 'python:kallithea.lib.hooks.log_pull_action', True),
 
            ('extensions', 'largefiles', '', True),
 
            ('largefiles', 'usercache', os.path.join(path, '.cache', 'largefiles'), True),
 
            ('extensions', 'hgsubversion', '', False),
 
            ('extensions', 'hggit', '', False),
 
        ]
 
        for section, key, value, active in ui_config:
 
            ui_conf = Ui()
 
            setattr(ui_conf, 'ui_section', section)
 
            setattr(ui_conf, 'ui_key', key)
 
            setattr(ui_conf, 'ui_value', value)
 
            setattr(ui_conf, 'ui_active', active)
 
            self.sa.add(ui_conf)
 

	
 
        settings = [
 
            ('realm', 'Kallithea', 'unicode'),
 
            ('title', '', 'unicode'),
 
            ('ga_code', '', 'unicode'),
 
            ('show_public_icon', True, 'bool'),
 
            ('show_private_icon', True, 'bool'),
 
            ('stylify_metalabels', False, 'bool'),
 
            ('dashboard_items', 100, 'int'), # TODO: call it page_size
 
            ('admin_grid_items', 25, 'int'),
 
            ('show_version', True, 'bool'),
 
            ('use_gravatar', True, 'bool'),
kallithea/lib/hooks.py
Show inline comments
 
@@ -337,74 +337,72 @@ def _hook_environment(repo_path):
 
    if repo_path.endswith(os.sep + '.git'):
 
        repo_path = repo_path[:-5]
 

	
 
    repo = Repository.get_by_full_path(repo_path)
 
    if not repo:
 
        raise OSError('Repository %s not found in database'
 
                      % (safe_str(repo_path)))
 

	
 
    baseui = make_ui('db')
 
    return baseui, repo
 

	
 

	
 
def handle_git_pre_receive(repo_path, git_stdin_lines):
 
    """Called from Git pre-receive hook"""
 
    return 0
 

	
 

	
 
def handle_git_post_receive(repo_path, git_stdin_lines):
 
    """Called from Git post-receive hook"""
 
    baseui, repo = _hook_environment(repo_path)
 

	
 
    # the post push hook should never use the cached instance
 
    scm_repo = repo.scm_instance_no_cache()
 

	
 
    _hooks = dict(baseui.configitems('hooks')) or {}
 
    # if push hook is enabled via web interface
 
    if _hooks.get(Ui.HOOK_PUSH_LOG):
 
        rev_data = []
 
        for l in git_stdin_lines:
 
            old_rev, new_rev, ref = l.strip().split(' ')
 
            _ref_data = ref.split('/')
 
            if _ref_data[1] in ['tags', 'heads']:
 
                rev_data.append({'old_rev': old_rev,
 
                                 'new_rev': new_rev,
 
                                 'ref': ref,
 
                                 'type': _ref_data[1],
 
                                 'name': '/'.join(_ref_data[2:])})
 

	
 
        git_revs = []
 
        for push_ref in rev_data:
 
            _type = push_ref['type']
 
            if _type == 'heads':
 
                if push_ref['old_rev'] == EmptyChangeset().raw_id:
 
                    # update the symbolic ref if we push new repo
 
                    if scm_repo.is_empty():
 
                        scm_repo._repo.refs.set_symbolic_ref('HEAD',
 
                                            'refs/heads/%s' % push_ref['name'])
 

	
 
                    # build exclude list without the ref
 
                    cmd = ['for-each-ref', '--format=%(refname)', 'refs/heads/*']
 
                    stdout, stderr = scm_repo.run_git_command(cmd)
 
                    ref = push_ref['ref']
 
                    heads = [head for head in stdout.splitlines() if head != ref]
 
                    # now list the git revs while excluding from the list
 
                    cmd = ['log', push_ref['new_rev'], '--reverse', '--pretty=format:%H']
 
                    cmd.append('--not')
 
                    cmd.extend(heads) # empty list is ok
 
                    stdout, stderr = scm_repo.run_git_command(cmd)
 
                    git_revs += stdout.splitlines()
 

	
 
                elif push_ref['new_rev'] == EmptyChangeset().raw_id:
 
                    # delete branch case
 
                    git_revs += ['delete_branch=>%s' % push_ref['name']]
 
                else:
 
                    cmd = ['log', '%(old_rev)s..%(new_rev)s' % push_ref,
 
                           '--reverse', '--pretty=format:%H']
 
                    stdout, stderr = scm_repo.run_git_command(cmd)
 
                    git_revs += stdout.splitlines()
 

	
 
            elif _type == 'tags':
 
                git_revs += ['tag=>%s' % push_ref['name']]
 

	
 
        log_push_action(baseui, scm_repo, _git_revs=git_revs)
 

	
 
    return 0
kallithea/lib/middleware/simplegit.py
Show inline comments
 
@@ -175,27 +175,26 @@ class SimpleGit(BaseVCSController):
 
            mapping = {
 
                'git-receive-pack': 'push',
 
                'git-upload-pack': 'pull',
 
            }
 
            op = mapping[service_cmd]
 
            self._git_stored_op = op
 
            # try to fallback to stored variable as we don't know if the last
 
            # operation is pull/push
 
        return self._git_stored_op
 

	
 
    def _handle_githooks(self, repo_name, action, baseui, environ):
 
        """
 
        Handles pull action, push is handled by post-receive hook
 
        """
 
        from kallithea.lib.hooks import log_pull_action
 
        service = environ['QUERY_STRING'].split('=')
 

	
 
        if len(service) < 2:
 
            return
 

	
 
        from kallithea.model.db import Repository
 
        _repo = Repository.get_by_repo_name(repo_name)
 
        _repo = _repo.scm_instance
 

	
 
        _hooks = dict(baseui.configitems('hooks')) or {}
 
        if action == 'pull' and _hooks.get(Ui.HOOK_PULL_LOG):
 
        if action == 'pull':
 
            log_pull_action(ui=baseui, repo=_repo._repo)
kallithea/lib/utils.py
Show inline comments
 
@@ -343,48 +343,51 @@ def make_ui(read_from='file', path=None,
 
                log.debug('settings ui from file: [%s] %s=%s', section, k, v)
 
                baseui.setconfig(safe_str(section), safe_str(k), safe_str(v))
 

	
 
    elif read_from == 'db':
 
        sa = meta.Session()
 
        ret = sa.query(Ui).all()
 

	
 
        hg_ui = ret
 
        for ui_ in hg_ui:
 
            if ui_.ui_active:
 
                ui_val = '' if ui_.ui_value is None else safe_str(ui_.ui_value)
 
                log.debug('settings ui from db: [%s] %s=%r', ui_.ui_section,
 
                          ui_.ui_key, ui_val)
 
                baseui.setconfig(safe_str(ui_.ui_section), safe_str(ui_.ui_key),
 
                                 ui_val)
 
        if clear_session:
 
            meta.Session.remove()
 

	
 
        # force set push_ssl requirement to False, Kallithea handles that
 
        baseui.setconfig('web', 'push_ssl', False)
 
        baseui.setconfig('web', 'allow_push', '*')
 
        # prevent interactive questions for ssh password / passphrase
 
        ssh = baseui.config('ui', 'ssh', default='ssh')
 
        baseui.setconfig('ui', 'ssh', '%s -oBatchMode=yes -oIdentitiesOnly=yes' % ssh)
 
        # push / pull hooks
 
        baseui.setconfig('hooks', 'changegroup.kallithea_log_push_action', 'python:kallithea.lib.hooks.log_push_action')
 
        baseui.setconfig('hooks', 'outgoing.kallithea_log_pull_action', 'python:kallithea.lib.hooks.log_pull_action')
 

	
 
    return baseui
 

	
 

	
 
def set_app_settings(config):
 
    """
 
    Updates app config with new settings from database
 

	
 
    :param config:
 
    """
 
    try:
 
        hgsettings = Setting.get_app_settings()
 
        for k, v in hgsettings.items():
 
            config[k] = v
 
    finally:
 
        meta.Session.remove()
 

	
 

	
 
def set_vcs_config(config):
 
    """
 
    Patch VCS config with some Kallithea specific stuff
 

	
 
    :param config: kallithea.CONFIG
 
    """
kallithea/model/db.py
Show inline comments
 
@@ -330,84 +330,80 @@ class Setting(Base, BaseDbModel):
 
        mods = [(p.project_name, p.version) for p in pkg_resources.working_set]
 
        info = {
 
            'modules': sorted(mods, key=lambda k: k[0].lower()),
 
            'py_version': platform.python_version(),
 
            'platform': safe_unicode(platform.platform()),
 
            'kallithea_version': kallithea.__version__,
 
            'git_version': safe_unicode(check_git_version()),
 
            'git_path': kallithea.CONFIG.get('git_path')
 
        }
 
        return info
 

	
 

	
 
class Ui(Base, BaseDbModel):
 
    __tablename__ = 'ui'
 
    __table_args__ = (
 
        # FIXME: ui_key as key is wrong and should be removed when the corresponding
 
        # Ui.get_by_key has been replaced by the composite key
 
        UniqueConstraint('ui_key'),
 
        UniqueConstraint('ui_section', 'ui_key'),
 
        _table_args_default_dict,
 
    )
 

	
 
    HOOK_UPDATE = 'changegroup.update'
 
    HOOK_REPO_SIZE = 'changegroup.repo_size'
 
    HOOK_PUSH_LOG = 'changegroup.push_logger'
 
    HOOK_PULL_LOG = 'outgoing.pull_logger'
 

	
 
    ui_id = Column(Integer(), primary_key=True)
 
    ui_section = Column(String(255), nullable=False)
 
    ui_key = Column(String(255), nullable=False)
 
    ui_value = Column(String(255), nullable=True) # FIXME: not nullable?
 
    ui_active = Column(Boolean(), nullable=False, default=True)
 

	
 
    @classmethod
 
    def get_by_key(cls, section, key):
 
        """ Return specified Ui object, or None if not found. """
 
        return cls.query().filter_by(ui_section=section, ui_key=key).scalar()
 

	
 
    @classmethod
 
    def get_or_create(cls, section, key):
 
        """ Return specified Ui object, creating it if necessary. """
 
        setting = cls.get_by_key(section, key)
 
        if setting is None:
 
            setting = cls(ui_section=section, ui_key=key)
 
            Session().add(setting)
 
        return setting
 

	
 
    @classmethod
 
    def get_builtin_hooks(cls):
 
        q = cls.query()
 
        q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
 
                                     cls.HOOK_PUSH_LOG, cls.HOOK_PULL_LOG]))
 
        q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE]))
 
        q = q.filter(cls.ui_section == 'hooks')
 
        return q.all()
 

	
 
    @classmethod
 
    def get_custom_hooks(cls):
 
        q = cls.query()
 
        q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
 
                                      cls.HOOK_PUSH_LOG, cls.HOOK_PULL_LOG]))
 
        q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE]))
 
        q = q.filter(cls.ui_section == 'hooks')
 
        return q.all()
 

	
 
    @classmethod
 
    def get_repos_location(cls):
 
        return cls.get_by_key('paths', '/').ui_value
 

	
 
    @classmethod
 
    def create_or_update_hook(cls, key, val):
 
        new_ui = cls.get_or_create('hooks', key)
 
        new_ui.ui_active = True
 
        new_ui.ui_value = val
 

	
 
    def __repr__(self):
 
        return '<%s[%s]%s=>%s]>' % (self.__class__.__name__, self.ui_section,
 
                                    self.ui_key, self.ui_value)
 

	
 

	
 
class User(Base, BaseDbModel):
 
    __tablename__ = 'users'
 
    __table_args__ = (
 
        Index('u_username_idx', 'username'),
 
        Index('u_email_idx', 'email'),
 
        _table_args_default_dict,
kallithea/model/forms.py
Show inline comments
 
@@ -364,50 +364,48 @@ def ApplicationVisualisationForm():
 
        stylify_metalabels = v.StringBoolean(if_missing=False)
 

	
 
        repository_fields = v.StringBoolean(if_missing=False)
 
        lightweight_journal = v.StringBoolean(if_missing=False)
 
        dashboard_items = v.Int(min=5, not_empty=True)
 
        admin_grid_items = v.Int(min=5, not_empty=True)
 
        show_version = v.StringBoolean(if_missing=False)
 
        use_gravatar = v.StringBoolean(if_missing=False)
 
        gravatar_url = v.UnicodeString(min=3)
 
        clone_uri_tmpl = v.UnicodeString(min=3)
 

	
 
    return _ApplicationVisualisationForm
 

	
 

	
 
def ApplicationUiSettingsForm():
 
    class _ApplicationUiSettingsForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = False
 
        paths_root_path = All(
 
            v.ValidPath(),
 
            v.UnicodeString(strip=True, min=1, not_empty=True)
 
        )
 
        hooks_changegroup_update = v.StringBoolean(if_missing=False)
 
        hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
 
        hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
 
        hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False)
 

	
 
        extensions_largefiles = v.StringBoolean(if_missing=False)
 
        extensions_hgsubversion = v.StringBoolean(if_missing=False)
 
        extensions_hggit = v.StringBoolean(if_missing=False)
 

	
 
    return _ApplicationUiSettingsForm
 

	
 

	
 
def DefaultPermissionsForm(repo_perms_choices, group_perms_choices,
 
                           user_group_perms_choices, create_choices,
 
                           create_on_write_choices, repo_group_create_choices,
 
                           user_group_create_choices, fork_choices,
 
                           register_choices, extern_activate_choices):
 
    class _DefaultPermissionsForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = True
 
        overwrite_default_repo = v.StringBoolean(if_missing=False)
 
        overwrite_default_group = v.StringBoolean(if_missing=False)
 
        overwrite_default_user_group = v.StringBoolean(if_missing=False)
 
        anonymous = v.StringBoolean(if_missing=False)
 
        default_repo_perm = v.OneOf(repo_perms_choices)
 
        default_group_perm = v.OneOf(group_perms_choices)
 
        default_user_group_perm = v.OneOf(user_group_perms_choices)
 

	
kallithea/templates/admin/settings/settings_vcs.html
Show inline comments
 
${h.form(url('admin_settings'), method='post')}
 
    <div class="form">
 
            <div class="form-group">
 
                <label class="control-label">${_('Hooks')}:</label>
 
                <div>
 
                    <div class="checkbox">
 
                        <label>
 
                            ${h.checkbox('hooks_changegroup_repo_size','True')}
 
                            ${_('Show repository size after push')}
 
                        </label>
 
                    </div>
 
                    <div class="checkbox">
 
                        <label>
 
                            ${h.checkbox('hooks_changegroup_push_logger','True')}
 
                            ${_('Log user push commands')}
 
                        </label>
 
                    </div>
 
                    <div class="checkbox">
 
                        <label>
 
                            ${h.checkbox('hooks_outgoing_pull_logger','True')}
 
                            ${_('Log user pull commands')}
 
                        </label>
 
                    </div>
 
                    <div class="checkbox">
 
                        <label>
 
                            ${h.checkbox('hooks_changegroup_update','True')}
 
                            ${_('Update repository after push (hg update)')}
 
                        </label>
 
                    </div>
 
                </div>
 
            </div>
 
            <div class="form-group">
 
                <label class="control-label">${_('Mercurial extensions')}:</label>
 
                <div>
 
                    <div class="checkbox">
 
                        <label>
 
                            ${h.checkbox('extensions_largefiles','True')}
 
                            ${_('Enable largefiles extension')}
 
                        </label>
 
                    </div>
 
                    <div class="checkbox">
 
                        <label>
 
                            ${h.checkbox('extensions_hgsubversion','True')}
 
                            ${_('Enable hgsubversion extension')}
 
                        </label>
 
                    </div>
 
                    <span class="help-block">${_('Requires hgsubversion library to be installed. Enables cloning of remote Subversion repositories while converting them to Mercurial.')}</span>
 
                    ##<div class="checkbox">
 
                    ##    <label>
0 comments (0 inline, 0 general)