|
# Copyright (c) 2008-2010 Fog Creek Software. All rights reserved.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2, incorporated herein by reference.
#
#
# This hook is only ever designed to be loaded and used by the Kiln runtime.
# Do not load it by installing it manually.
import simplejson
import settings
from mercurial import pushkey
import urlutil
from webtasks import asyncpost, queue_repo_index
import bfiles
from api.repositories import Repository
import syncstatus
def _revtuple(rev):
"Return a (rev num, rev id) tuple from a changeset context"
return (rev.rev(), rev.hex())
def _ctx(ctx):
return {'user': _uc(ctx.user()),
'date': ctx.date(),
'rev': (ctx.rev(), ctx.hex()),
'description': _uc(ctx.description()),
'branch': _uc(ctx.branch()),
'extra': dict((_uc(k), _uc(v)) for k, v in ctx.extra().iteritems()),
'tags': [_uc(s) for s in ctx.tags()],
'parents': [(p.rev(), p.hex()) for p in ctx.parents()]}
def _uc(s):
return unicode(s, encoding='utf8', errors='replace')
def prechangehook(ui, repo, hooktype, node, **kwargs):
"Check that the user uploaded all bfiles before pushing to the repo"
if hooktype not in ('pretxnchangegroup', 'pretxncommit'):
ui.warn('kiln postback hook was inappropriately attached\n')
ui.flush()
return True
base = repo[node].rev()
tip = repo['tip'].rev()
uuid = repo.url().replace('\\', '/').split('/')[-1]
success = True
#The repo we are passed has uncommited changes that the default repo doesn't have yet, so set the repo
r = Repository(uuid, repo=repo)
for rev in xrange(base, tip+1):
for bfile in r.listbfiles(rev):
if not bfiles.instore(r.getbfilesha(bfile, rev)):
ui.warn('ERROR: Big file %s at revision %s has not been uploaded to the kiln server.\n' % (bfile, rev))
success = False
if not success:
ui.warn('ERROR: All big files must be uploaded to the kiln server before the repository is changed.\n')
return True
def changehook(ui, repo, hooktype, node, **kwargs):
"Notify kiln that there have been changes to this repository"
if hooktype not in ('changegroup', 'commit', 'strip'):
ui.warn('kiln postback hook was inappropriately attached\n')
return False
base = repo[node].rev()
tip = repo['tip'].rev()
uuid = repo.url().replace('\\', '/').split('/')[-1]
person = int(ui.config('kiln', 'ixperson')) if ui.config('kiln', 'ixperson') else None
source = ui.config('kiln', 'source')
bookmarks = [tag for tag in pushkey.list(repo, 'bookmarks').keys()]
tags = [{'tag': tag,
'rev': (repo[node].rev(), repo[node].hex()),
'bookmark': True}
for (tag, node) in pushkey.list(repo, 'bookmarks').items() if node in repo]
tags.extend(
[{'tag': tag,
'rev': (repo[node].rev(), repo[node].hex()),
'bookmark': False}
for (tag, node) in repo.tags().iteritems() if tag not in bookmarks and node in repo])
d = {'heads': [_revtuple(repo[head]) for head in repo.heads()],
'tails': [_revtuple(repo[0])],
'repo': uuid, 'url': kwargs.get('url'),
'person': person,
'source': ui.config('kiln', 'source'),
'tags': tags}
d['changesets'] = [_ctx(repo[rev]) for rev in xrange(base, tip + 1)]
if ui.config('kiln', 'client') != 'website':
changecount = tip + 1 - base
if changecount > 1:
ui.write('kiln: successfully pushed %d changesets\n' % changecount)
else:
ui.write('kiln: successfully pushed one changeset\n')
url = urlutil.urljoin(ui.config('kiln', 'url'), 'Pingback/Push')
asyncpost(url, {'data': simplejson.dumps(d), 'token': ui.config('kiln', 'token')})
if settings.DO_INDEXING:
queue_repo_index(uuid)
r = Repository(uuid, repo=repo)
if settings.HOSTED:
syncstatus.update_status(r)
site = ui.config('kiln', 'site')
if site:
peers = dict(ui.configitems('peers'))
r.sync(site, peers)
|
Loading...