# # Copyright (c) 2010, Sebastian Sdorra # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # 3. Neither the name of SCM-Manager; nor the names of its # contributors may be used to endorse or promote products derived from this # software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # http://bitbucket.org/sdorra/scm-manager # # # # registration .hg/hgrc: # # [hooks] # changegroup.scm = python:scmhooks.callback # import os, urllib, urllib2 baseUrl = os.environ['SCM_URL'] challenge = os.environ['SCM_CHALLENGE'] credentials = os.environ['SCM_CREDENTIALS'] repositoryId = os.environ['SCM_REPOSITORY_ID'] def printMessages(ui, msgs): for line in msgs: if line.startswith("_e") or line.startswith("_n"): line = line[2:]; ui.warn('%s\n' % line.rstrip()) def callHookUrl(ui, repo, hooktype, node): abort = True try: url = baseUrl + hooktype ui.debug( "send scm-hook to " + url + " and " + node + "\n" ) data = urllib.urlencode({'node': node, 'challenge': challenge, 'credentials': credentials, 'repositoryPath': repo.root, 'repositoryId': repositoryId}) # open url but ignore proxy settings proxy_handler = urllib2.ProxyHandler({}) opener = urllib2.build_opener(proxy_handler) req = urllib2.Request(url, data) conn = opener.open(req) if conn.code >= 200 and conn.code < 300: ui.debug( "scm-hook " + hooktype + " success with status code " + str(conn.code) + "\n" ) printMessages(ui, conn) abort = False else: ui.warn( "ERROR: scm-hook failed with error code " + str(conn.code) + "\n" ) except urllib2.URLError, e: msg = None # some URLErrors have no read method if hasattr(e, "read"): msg = e.read() elif hasattr(e, "code"): msg = "scm-hook failed with error code " + str(e.code) + "\n" else: msg = str(e) if len(msg) > 0: printMessages(ui, msg.splitlines(True)) else: ui.warn( "ERROR: scm-hook failed with an unknown error\n" ) ui.traceback() except ValueError: ui.warn( "scm-hook failed with an exception\n" ) ui.traceback() return abort def callback(ui, repo, hooktype, node=None): abort = True if node != None: if len(baseUrl) > 0: abort = callHookUrl(ui, repo, hooktype, node) else: ui.warn("ERROR: scm-manager hooks are disabled, please check your configuration and the scm-manager log for details\n") abort = False else: ui.warn("changeset node is not available") return abort def preHook(ui, repo, hooktype, node=None, source=None, pending=None, **kwargs): # older mercurial versions if pending != None: pending() # newer mercurial version # we have to make in-memory changes visible to external process # this does not happen automatically, because mercurial treat our hooks as internal hooks # see hook.py at mercurial sources _exthook try: if repo is not None: tr = repo.currenttransaction() repo.dirstate.write(tr) if tr and not tr.writepending(): ui.warn("no pending write transaction found") except AttributeError: ui.debug("mercurial does not support currenttransation") # do nothing return callback(ui, repo, hooktype, node) def postHook(ui, repo, hooktype, node=None, source=None, pending=None, **kwargs): return callback(ui, repo, hooktype, node)