##// END OF EJS Templates
added API call for locking/unlocking repositories
added API call for locking/unlocking repositories

File last commit:

r2726:aa17c7a1 beta
r2737:e21cb7b1 beta
Show More
hooks.py
377 lines | 11.7 KiB | text/x-python | PythonLexer
filled in some docs for hooks
r913 # -*- coding: utf-8 -*-
"""
rhodecode.lib.hooks
~~~~~~~~~~~~~~~~~~~
Hooks runned by rhodecode
source code cleanup: remove trailing white space, normalize file endings
r1203
filled in some docs for hooks
r913 :created_on: Aug 6, 2010
:author: marcink
2012 copyrights
r1824 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
filled in some docs for hooks
r913 :license: GPLv3, see COPYING for more details.
"""
fixed license issue #149
r1206 # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
source code cleanup: remove trailing white space, normalize file endings
r1203 #
renamed project to rhodecode
r547 # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
source code cleanup: remove trailing white space, normalize file endings
r1203 #
renamed project to rhodecode
r547 # You should have received a copy of the GNU General Public License
fixed license issue #149
r1206 # along with this program. If not, see <http://www.gnu.org/licenses/>.
filled in some docs for hooks
r913 import os
import sys
save full raw id in push log data for much faster revision lookup
r2324 import binascii
from inspect import isfunction
renamed project to rhodecode
r547
fixed hooks for mercurial 1.9
r1415 from mercurial.scmutil import revrange
#48 rewrite action loggers into hooks with all changesets that are inside a push
r654 from mercurial.node import nullrev
save full raw id in push log data for much faster revision lookup
r2324
#48 rewrite action loggers into hooks with all changesets that are inside a push
r654 from rhodecode.lib import helpers as h
from rhodecode.lib.utils import action_logger
Git Hooks are automatically installed in new repos...
r2404 from rhodecode.lib.vcs.backends.base import EmptyChangeset
use os.environ as a fallback for getting special info from hooks, this will allow...
r2716 from rhodecode.lib.compat import json
Implemented basic locking functionality....
r2726 from rhodecode.model.db import Repository, User
from rhodecode.lib.utils2 import safe_str
from rhodecode.lib.exceptions import HTTPLockedRC
renamed project to rhodecode
r547
pep8ify
r1307
made repo-size hook more generic
r2196 def _get_scm_size(alias, root_path):
if not alias.startswith('.'):
alias += '.'
size_scm, size_root = 0, 0
for path, dirs, files in os.walk(root_path):
if path.find(alias) != -1:
for f in files:
try:
size_scm += os.path.getsize(os.path.join(path, f))
except OSError:
pass
else:
for f in files:
try:
size_root += os.path.getsize(os.path.join(path, f))
except OSError:
pass
size_scm_f = h.format_byte_size(size_scm)
size_root_f = h.format_byte_size(size_root)
size_total_f = h.format_byte_size(size_root + size_scm)
return size_scm_f, size_root_f, size_total_f
renamed project to rhodecode
r547 def repo_size(ui, repo, hooktype=None, **kwargs):
#235 forking page repo group selection...
r1722 """
Presents size of repository after push
source code cleanup: remove trailing white space, normalize file endings
r1203
filled in some docs for hooks
r913 :param ui:
:param repo:
:param hooktype:
"""
renamed project to rhodecode
r547
made repo-size hook more generic
r2196 size_hg_f, size_root_f, size_total_f = _get_scm_size('.hg', repo.root)
small change for post update hook that displays repository size
r1814
last_cs = repo[len(repo) - 1]
msg = ('Repository size .hg:%s repo:%s total:%s\n'
'Last revision is now r%s:%s\n') % (
size_hg_f, size_root_f, size_total_f, last_cs.rev(), last_cs.hex()[:12]
)
sys.stdout.write(msg)
bugfix, repo_size crashed when broken symlinks where inside a repository.
r675
pep8ify
r1307
Implemented basic locking functionality....
r2726 def pre_push(ui, repo, **kwargs):
# pre push function, currently used to ban pushing when
# repository is locked
try:
rc_extras = json.loads(os.environ.get('RC_SCM_DATA', "{}"))
except:
rc_extras = {}
extras = dict(repo.ui.configitems('rhodecode_extras'))
if 'username' in extras:
username = extras['username']
repository = extras['repository']
scm = extras['scm']
locked_by = extras['locked_by']
elif 'username' in rc_extras:
username = rc_extras['username']
repository = rc_extras['repository']
scm = rc_extras['scm']
locked_by = rc_extras['locked_by']
else:
raise Exception('Missing data in repo.ui and os.environ')
usr = User.get_by_username(username)
if locked_by[0] and usr.user_id != int(locked_by[0]):
raise HTTPLockedRC(username, repository)
def pre_pull(ui, repo, **kwargs):
# pre push function, currently used to ban pushing when
# repository is locked
try:
rc_extras = json.loads(os.environ.get('RC_SCM_DATA', "{}"))
except:
rc_extras = {}
extras = dict(repo.ui.configitems('rhodecode_extras'))
if 'username' in extras:
username = extras['username']
repository = extras['repository']
scm = extras['scm']
locked_by = extras['locked_by']
elif 'username' in rc_extras:
username = rc_extras['username']
repository = rc_extras['repository']
scm = rc_extras['scm']
locked_by = rc_extras['locked_by']
else:
raise Exception('Missing data in repo.ui and os.environ')
if locked_by[0]:
raise HTTPLockedRC(username, repository)
#48 rewrite action loggers into hooks with all changesets that are inside a push
r654 def log_pull_action(ui, repo, **kwargs):
#235 forking page repo group selection...
r1722 """
Logs user last pull action
source code cleanup: remove trailing white space, normalize file endings
r1203
#48 rewrite action loggers into hooks with all changesets that are inside a push
r654 :param ui:
:param repo:
"""
use os.environ as a fallback for getting special info from hooks, this will allow...
r2716 try:
rc_extras = json.loads(os.environ.get('RC_SCM_DATA', "{}"))
except:
rc_extras = {}
added initial rc-extension module...
r2105 extras = dict(repo.ui.configitems('rhodecode_extras'))
use os.environ as a fallback for getting special info from hooks, this will allow...
r2716 if 'username' in extras:
username = extras['username']
repository = extras['repository']
scm = extras['scm']
Implemented basic locking functionality....
r2726 make_lock = extras['make_lock']
use os.environ as a fallback for getting special info from hooks, this will allow...
r2716 elif 'username' in rc_extras:
username = rc_extras['username']
repository = rc_extras['repository']
scm = rc_extras['scm']
Implemented basic locking functionality....
r2726 make_lock = rc_extras['make_lock']
use os.environ as a fallback for getting special info from hooks, this will allow...
r2716 else:
raise Exception('Missing data in repo.ui and os.environ')
Implemented basic locking functionality....
r2726 user = User.get_by_username(username)
#48 rewrite action loggers into hooks with all changesets that are inside a push
r654 action = 'pull'
Implemented basic locking functionality....
r2726 action_logger(user, action, repository, extras['ip'], commit=True)
added initial rc-extension module...
r2105 # extension hook call
changed scope of calling EXTENSIONS from rhodecode for githooks to be able to execute them
r2406 from rhodecode import EXTENSIONS
added initial rc-extension module...
r2105 callback = getattr(EXTENSIONS, 'PULL_HOOK', None)
bugfix, repo_size crashed when broken symlinks where inside a repository.
r675
added initial rc-extension module...
r2105 if isfunction(callback):
kw = {}
kw.update(extras)
callback(**kw)
Implemented basic locking functionality....
r2726
if make_lock is True:
Repository.lock(Repository.get_by_repo_name(repository), user.user_id)
#msg = 'Made lock on repo `%s`' % repository
#sys.stdout.write(msg)
#48 rewrite action loggers into hooks with all changesets that are inside a push
r654 return 0
renamed project to rhodecode
r547
pep8ify
r1307
#48 rewrite action loggers into hooks with all changesets that are inside a push
r654 def log_push_action(ui, repo, **kwargs):
#235 forking page repo group selection...
r1722 """
Maps user last push action to new changeset id, from mercurial
source code cleanup: remove trailing white space, normalize file endings
r1203
fixed @repo into :repo for docs...
r604 :param ui:
fixes issue #436 git push error
r2236 :param repo: repo object containing the `ui` object
renamed project to rhodecode
r547 """
bugfix, repo_size crashed when broken symlinks where inside a repository.
r675
use os.environ as a fallback for getting special info from hooks, this will allow...
r2716 try:
rc_extras = json.loads(os.environ.get('RC_SCM_DATA', "{}"))
except:
rc_extras = {}
added initial rc-extension module...
r2105 extras = dict(repo.ui.configitems('rhodecode_extras'))
use os.environ as a fallback for getting special info from hooks, this will allow...
r2716 if 'username' in extras:
username = extras['username']
repository = extras['repository']
scm = extras['scm']
Implemented basic locking functionality....
r2726 make_lock = extras['make_lock']
use os.environ as a fallback for getting special info from hooks, this will allow...
r2716 elif 'username' in rc_extras:
username = rc_extras['username']
repository = rc_extras['repository']
scm = rc_extras['scm']
Implemented basic locking functionality....
r2726 make_lock = rc_extras['make_lock']
use os.environ as a fallback for getting special info from hooks, this will allow...
r2716 else:
raise Exception('Missing data in repo.ui and os.environ')
action = 'push' + ':%s'
bugfix, repo_size crashed when broken symlinks where inside a repository.
r675
added emulation of pull hook for git-backend, and dummy git-push hook
r2203 if scm == 'hg':
node = kwargs['node']
def get_revs(repo, rev_opt):
if rev_opt:
revs = revrange(repo, rev_opt)
bugfix, repo_size crashed when broken symlinks where inside a repository.
r675
added emulation of pull hook for git-backend, and dummy git-push hook
r2203 if len(revs) == 0:
return (nullrev, nullrev)
return (max(revs), min(revs))
else:
return (len(repo) - 1, 0)
bugfix, repo_size crashed when broken symlinks where inside a repository.
r675
added emulation of pull hook for git-backend, and dummy git-push hook
r2203 stop, start = get_revs(repo, [node + ':'])
save full raw id in push log data for much faster revision lookup
r2324 h = binascii.hexlify
Change git & hg hooks to post. They shouldn't block as they are used just for logging actions. Futhermore post hooks have access to changesets, so it's much better flexible
r2407 revs = [h(repo[r].node()) for r in xrange(start, stop + 1)]
added emulation of pull hook for git-backend, and dummy git-push hook
r2203 elif scm == 'git':
Added handling of git hooks, extract pushed revisions and store them inside...
r2402 revs = kwargs.get('_git_revs', [])
if '_git_revs' in kwargs:
kwargs.pop('_git_revs')
bugfix, repo_size crashed when broken symlinks where inside a repository.
r675
#48 rewrite action loggers into hooks with all changesets that are inside a push
r654 action = action % ','.join(revs)
bugfix, repo_size crashed when broken symlinks where inside a repository.
r675
added initial rc-extension module...
r2105 action_logger(username, action, repository, extras['ip'], commit=True)
bugfix, repo_size crashed when broken symlinks where inside a repository.
r675
added initial rc-extension module...
r2105 # extension hook call
changed scope of calling EXTENSIONS from rhodecode for githooks to be able to execute them
r2406 from rhodecode import EXTENSIONS
added initial rc-extension module...
r2105 callback = getattr(EXTENSIONS, 'PUSH_HOOK', None)
if isfunction(callback):
kw = {'pushed_revs': revs}
kw.update(extras)
callback(**kw)
Implemented basic locking functionality....
r2726
if make_lock is False:
Repository.unlock(Repository.get_by_repo_name(repository))
msg = 'Released lock on repo `%s`\n' % repository
sys.stdout.write(msg)
#48 rewrite action loggers into hooks with all changesets that are inside a push
r654 return 0
#348 added post-create repository hook
r1972
def log_create_repository(repository_dict, created_by, **kwargs):
"""
Post create repository Hook. This is a dummy function for admins to re-use
utils/conf...
r2109 if needed. It's taken from rhodecode-extensions module and executed
added initial rc-extension module...
r2105 if present
#348 added post-create repository hook
r1972
#227 Initial version of repository groups permissions system...
r1982 :param repository: dict dump of repository object
#348 added post-create repository hook
r1972 :param created_by: username who created repository
:param created_date: date of creation
available keys of repository_dict:
'repo_type',
'description',
'private',
'created_on',
'enable_downloads',
'repo_id',
'user_id',
'enable_statistics',
'clone_uri',
'fork_id',
'group_id',
'repo_name'
"""
changed scope of calling EXTENSIONS from rhodecode for githooks to be able to execute them
r2406 from rhodecode import EXTENSIONS
added initial rc-extension module...
r2105 callback = getattr(EXTENSIONS, 'CREATE_REPO_HOOK', None)
if isfunction(callback):
kw = {}
kw.update(repository_dict)
kw.update({'created_by': created_by})
kw.update(kwargs)
return callback(**kw)
#348 added post-create repository hook
r1972
#227 Initial version of repository groups permissions system...
r1982 return 0
Added handling of git hooks, extract pushed revisions and store them inside...
r2402
Implemented basic locking functionality....
r2726 handle_git_pre_receive = (lambda repo_path, revs, env:
handle_git_receive(repo_path, revs, env, hook_type='pre'))
handle_git_post_receive = (lambda repo_path, revs, env:
handle_git_receive(repo_path, revs, env, hook_type='post'))
Added handling of git hooks, extract pushed revisions and store them inside...
r2402
Implemented basic locking functionality....
r2726
def handle_git_receive(repo_path, revs, env, hook_type='post'):
Added handling of git hooks, extract pushed revisions and store them inside...
r2402 """
Change git & hg hooks to post. They shouldn't block as they are used just for logging actions. Futhermore post hooks have access to changesets, so it's much better flexible
r2407 A really hacky method that is runned by git post-receive hook and logs
whitespace cleanup
r2409 an push action together with pushed revisions. It's executed by subprocess
thus needs all info to be able to create a on the fly pylons enviroment,
connect to database and run the logging code. Hacky as sh*t but works.
Added handling of git hooks, extract pushed revisions and store them inside...
r2402
:param repo_path:
:type repo_path:
:param revs:
:type revs:
:param env:
:type env:
"""
from paste.deploy import appconfig
from sqlalchemy import engine_from_config
from rhodecode.config.environment import load_environment
from rhodecode.model import init_model
from rhodecode.model.db import RhodeCodeUi
from rhodecode.lib.utils import make_ui
path, ini_name = os.path.split(env['RHODECODE_CONFIG_FILE'])
conf = appconfig('config:%s' % ini_name, relative_to=path)
load_environment(conf.global_conf, conf.local_conf)
engine = engine_from_config(conf, 'sqlalchemy.db1.')
init_model(engine)
baseui = make_ui('db')
Fixed githooks for fetching multiple tags and branches....
r2617 # fix if it's not a bare repo
if repo_path.endswith('.git'):
repo_path = repo_path[:-4]
Added handling of git hooks, extract pushed revisions and store them inside...
r2402 repo = Repository.get_by_full_path(repo_path)
_hooks = dict(baseui.configitems('hooks')) or {}
Implemented basic locking functionality....
r2726 extras = json.loads(env['RHODECODE_EXTRAS'])
for k, v in extras.items():
baseui.setconfig('rhodecode_extras', k, v)
repo = repo.scm_instance
repo.ui = baseui
if hook_type == 'pre':
pre_push(baseui, repo)
# if push hook is enabled via web interface
elif hook_type == 'post' and _hooks.get(RhodeCodeUi.HOOK_PUSH):
Fixed githooks for fetching multiple tags and branches....
r2617
rev_data = []
for l in revs:
old_rev, new_rev, ref = l.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': _ref_data[2].strip()})
git_revs = []
for push_ref in rev_data:
_type = push_ref['type']
if _type == 'heads':
if push_ref['old_rev'] == EmptyChangeset().raw_id:
cmd = "for-each-ref --format='%(refname)' 'refs/heads/*'"
heads = repo.run_git_command(cmd)[0]
heads = heads.replace(push_ref['ref'], '')
heads = ' '.join(map(lambda c: c.strip('\n').strip(),
heads.splitlines()))
cmd = (('log %(new_rev)s' % push_ref) +
' --reverse --pretty=format:"%H" --not ' + heads)
else:
cmd = (('log %(old_rev)s..%(new_rev)s' % push_ref) +
' --reverse --pretty=format:"%H"')
git_revs += repo.run_git_command(cmd)[0].splitlines()
elif _type == 'tags':
git_revs += [push_ref['name']]
Added handling of git hooks, extract pushed revisions and store them inside...
r2402
log_push_action(baseui, repo, _git_revs=git_revs)