diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/blame.py b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/blame.py new file mode 100644 index 0000000000..46cf32f283 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/blame.py @@ -0,0 +1,63 @@ +# +# 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 +# +# + +import os +from util import * +from xml.dom.minidom import Document + +def appendBlameLine(doc, parent, lineCtx, lineNumber): + ctx = lineCtx[0].changectx() + lineNode = createChildNode(doc, parent, 'blameline') + appendTextNode(doc, lineNode, 'lineNumber', str(lineNumber)) + appendTextNode(doc, lineNode, 'revision', getId(ctx)) + appendDateNode(doc, lineNode, 'when', ctx.date()) + appendAuthorNodes(doc, lineNode, ctx) + appendTextNode(doc, lineNode, 'description', ctx.description()) + appendTextNode(doc, lineNode, 'code', lineCtx[1][:-1]) + +def appendBlameLines(doc, repo, revision, path): + blameResult = createChildNode(doc, doc, 'blame-result') + linesCtx = repo[revision][path].annotate() + lineNumber = 0 + for lineCtx in linesCtx: + lineNumber += 1 + appendBlameLine(doc, blameResult, lineCtx, lineNumber) + appendTextNode(doc, blameResult, 'total', str(lineNumber)) + +# main method + +repo = openRepository() +revision = os.environ['SCM_REVISION'] +path = os.environ['SCM_PATH'] + +doc = Document() +appendBlameLines(doc, repo, revision, path) +writeXml(doc) \ No newline at end of file diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/changelog.py b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/changelog.py new file mode 100644 index 0000000000..9f469c127e --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/changelog.py @@ -0,0 +1,150 @@ +# +# 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 +# +# + + +import os +from util import * +from xml.dom.minidom import Document + +# changeset methods + +def appendIdNode(doc, parentNode, ctx): + id = getId(ctx) + appendTextNode(doc, parentNode, 'id', id) + +def appendParentNodes(doc, parentNode, ctx): + parents = ctx.parents() + if parents: + for parent in parents: + parentId = getId(parent) + appendTextNode(doc, parentNode, 'parents', parentId) + +def appendBranchesNode(doc, parentNode, ctx): + branch = ctx.branch() + if branch != 'default': + appendTextNode(doc, parentNode, 'branches', branch) + +def appendModifications(doc, parentNode, ctx): + status = repo.status(ctx.p1().node(), ctx.node()) + if status: + modificationsNode = createChildNode(doc, parentNode, 'modifications') + appendWrappedListNodes(doc, modificationsNode, 'added', 'file', status[1]) + appendWrappedListNodes(doc, modificationsNode, 'modified', 'file', status[0]) + appendWrappedListNodes(doc, modificationsNode, 'removed', 'file', status[2]) + +def appendChangesetNode(doc, parentNode, ctx): + changesetNode = createChildNode(doc, parentNode, 'changeset') + appendIdNode(doc, changesetNode, ctx) + appendParentNodes(doc, changesetNode, ctx) + appendTextNode(doc, changesetNode, 'description', ctx.description()) + appendDateNode(doc, changesetNode, 'date', ctx.date()) + appendAuthorNodes(doc, changesetNode, ctx) + appendBranchesNode(doc, changesetNode, ctx) + appendListNodes(doc, changesetNode, 'tags', ctx.tags()) + appendModifications(doc, changesetNode, ctx) + +# changeset methods end + +# change log methods + +def createBasicNodes(doc, ctxs): + rootNode = doc.createElement('changeset-paging') + doc.appendChild(rootNode) + total = str(len(repo)) + appendTextNode(doc, rootNode, 'total', total) + return createChildNode(doc, rootNode, 'changesets') + +def appendChangesetsForPath(doc, repo, rev, path): + if len(rev) <= 0: + rev = "tip" + fctxs = repo[rev].filectx(path) + maxRev = fctxs.rev() + revs = [] + for i in fctxs.filelog(): + fctx = fctxs.filectx(i) + if fctx.rev() <= maxRev: + revs.append(fctx.changectx()) + # reverse changesets + revs.reverse() + # handle paging + start = os.environ['SCM_PAGE_START'] + limit = os.environ['SCM_PAGE_LIMIT'] + if len(start) > 0: + revs = revs[int(start):] + if len(limit) > 0: + revs = revs[:int(limit)] + # output + changesets = createBasicNodes(doc, revs) + for ctx in revs: + appendChangesetNode(doc, changesets, ctx) + +def appendChangesetsForStartAndEnd(doc, repo, startRev, endRev): + changesets = createBasicNodes(doc, repo) + for i in range(endRev, startRev, -1): + appendChangesetNode(doc, changesets, repo[i]) + +# change log methods + +# main method +repo = openRepository() +doc = Document() + +path = os.environ['SCM_PATH'] +startNode = os.environ['SCM_REVISION_START'] +endNode = os.environ['SCM_REVISION_END'] +rev = os.environ['SCM_REVISION'] + +if len(path) > 0: + appendChangesetsForPath(doc, repo, rev, path) +elif len(rev) > 0: + ctx = repo[rev] + appendChangesetNode(doc, doc, ctx) +else: + if len(startNode) > 0 and len(endNode) > 0: + # start and end revision + startRev = repo[startNode].rev() -1 + endRev = repo[endNode].rev() + else: + # paging + start = os.environ['SCM_PAGE_START'] + limit = os.environ['SCM_PAGE_LIMIT'] + limit = int(limit) + end = int(start) + endRev = len(repo) - end - 1 + startRev = endRev - limit + # fix negative start revisions + if startRev < -1: + startRev = -1 + # print + appendChangesetsForStartAndEnd(doc, repo, startRev, endRev) + +# write document +writeXml(doc) diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/filelog.py b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/filelog.py new file mode 100644 index 0000000000..6fe5fa1f29 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/filelog.py @@ -0,0 +1,157 @@ +# +# 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 +# +# + +import os +from util import * +from xml.dom.minidom import Document + +class SubRepository: + url = None + revision = None + +def getName(path): + parts = path.split('/') + length = len(parts) + if path.endswith('/'): + length =- 1 + return parts[length - 1] + +def appendSubRepositoryNode(doc, parentNode, path, subRepositories): + if path in subRepositories: + subRepository = subRepositories[path] + subRepositoryNode = createChildNode(doc, parentNode, 'subrepository') + if subRepository.revision != None: + appendTextNode(doc, subRepositoryNode, 'revision', subRepository.revision) + appendTextNode(doc, subRepositoryNode, 'repository-url', subRepository.url) + +def createBasicFileNode(doc, parentNode, path, directory): + fileNode = createChildNode(doc, parentNode, 'file') + appendTextNode(doc, fileNode, 'name', getName(path)) + appendTextNode(doc, fileNode, 'path', path) + appendTextNode(doc, fileNode, 'directory', directory) + return fileNode + +def appendDirectoryNode(doc, parentNode, path, subRepositories): + fileNode = createBasicFileNode(doc, parentNode, path, 'true') + appendSubRepositoryNode(doc, fileNode, path, subRepositories) + +def appendFileNode(doc, parentNode, repo, file): + linkrev = repo[file.linkrev()] + fileNode = createBasicFileNode(doc, parentNode, file.path(), 'false') + appendTextNode(doc, fileNode, 'length', str(file.size())) + appendDateNode(doc, fileNode, 'lastModified', linkrev.date()) + appendTextNode(doc, fileNode, 'description', linkrev.description()) + +def createSubRepositoryMap(revCtx): + subrepos = {} + try: + hgsub = revCtx.filectx('.hgsub').data().split('\n') + for line in hgsub: + parts = line.split('=') + if len(parts) > 1: + subrepo = SubRepository() + subrepo.url = parts[1].strip() + subrepos[parts[0].strip()] = subrepo + except Exception: + pass + + try: + hgsubstate = revCtx.filectx('.hgsubstate').data().split('\n') + for line in hgsubstate: + parts = line.split(' ') + if len(parts) > 1: + subrev = parts[0].strip() + subrepo = subrepos[parts[1].strip()] + subrepo.revision = subrev + except Exception: + pass + + return subrepos + +def appendSubRepositoryDirectories(directories, subRepositories): + for k, v in subRepositories.iteritems(): + if k.startswith(path): + directories.append(k) + +def collectFiles(repo, revCtx, files, directories): + length = 0 + paths = [] + mf = revCtx.manifest() + if path is "": + length = 1 + for f in mf: + paths.append(f) + else: + length = len(path.split('/')) + 1 + for f in mf: + if f.startswith(path): + paths.append(f) + + for p in paths: + parts = p.split('/') + depth = len(parts) + if depth is length: + file = repo[revision][p] + files.append(file) + elif depth > length: + dirpath = '' + for i in range(0, length): + dirpath += parts[i] + '/' + if not dirpath in directories: + directories.append(dirpath) + +def appendFileNodes(doc, parentNode, repo, revision): + files = [] + directories = [] + revCtx = repo[revision] + subRepositories = createSubRepositoryMap(revCtx) + appendSubRepositoryDirectories(directories, subRepositories) + collectFiles(repo, revCtx, files, directories) + for dir in directories: + appendDirectoryNode(doc, parentNode, dir, subRepositories) + for file in files: + appendFileNode(doc, parentNode, repo, file) + + +# main method + +repo = openRepository() +revision = os.environ['SCM_REVISION'] +path = os.environ['SCM_PATH'] + +# create document and append nodes + +doc = Document() +browserResultNode = createChildNode(doc, doc, 'browser-result') +appendTextNode(doc, browserResultNode, 'revision', revision) +filesNode = createChildNode(doc, browserResultNode, 'files') +appendFileNodes(doc, filesNode, repo, revision) +writeXml(doc) diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/hgweb.py b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/hgweb.py new file mode 100644 index 0000000000..e9e3ce8388 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/hgweb.py @@ -0,0 +1,47 @@ +#!/usr/bin/env ${python} +# +# 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 +# +# + + +import os, sys +pythonPath = os.environ['SCM_PYTHON_PATH'] + +if len(pythonPath) > 0: + pathParts = pythonPath.split(os.pathsep) + for i in range(len(pathParts)): + sys.path.insert(i, pathParts[i]) + +repositoryPath = os.environ['SCM_REPOSITORY_PATH'] + +from mercurial import demandimport; demandimport.enable() +from mercurial.hgweb import hgweb, wsgicgi +application = hgweb(repositoryPath) +wsgicgi.launch(application) diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/hook.py b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/hook.py new file mode 100644 index 0000000000..fe25aafef2 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/hook.py @@ -0,0 +1,62 @@ +# +# 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 + +baseUrl = os.environ['SCM_URL'] +challenge = os.environ['SCM_CHALLENGE'] +credentials = os.environ['SCM_CREDENTIALS'] + +def callback(ui, repo, hooktype, node=None, source=None, pending=None, **kwargs): + if pending != None: + pending() + failure = True + if node != None: + 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}) + conn = urllib.urlopen(url, data); + if conn.code >= 200 and conn.code < 300: + ui.debug( "scm-hook " + hooktype + " success with status code " + str(conn.code) + "\n" ) + failure = False + else: + ui.warn( "scm-hook failed with error code " + str(conn.code) + "\n" ) + except ValueError: + ui.warn( "scm-hook failed with an exception\n" ) + return failure diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/util.py b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/util.py new file mode 100644 index 0000000000..553d6ba4a7 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/util.py @@ -0,0 +1,99 @@ +# +# 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 +# +# + +# import basic modules +import sys, os + +# create python path +pythonPath = os.environ['SCM_PYTHON_PATH'] + +if len(pythonPath) > 0: + pathParts = pythonPath.split(os.pathsep) + for i in range(len(pathParts)): + sys.path.insert(i, pathParts[i]) + +# import mercurial modules +from mercurial import hg, ui, commands +from mercurial.node import hex +from xml.dom.minidom import Document + +# util methods +def openRepository(): + repositoryPath = os.environ['SCM_REPOSITORY_PATH'] + return hg.repository(ui.ui(), path = repositoryPath) + +def writeXml(doc): + # print doc.toprettyxml(indent=" ") + doc.writexml(sys.stdout, encoding='UTF-8') + +def createChildNode(doc, parentNode, name): + node = doc.createElement(name) + parentNode.appendChild(node) + return node + +def appendValue(doc, node, value): + textNode = doc.createTextNode(value) + node.appendChild(textNode) + +def appendTextNode(doc, parentNode, name, value): + node = createChildNode(doc, parentNode, name) + appendValue(doc, node, value) + +def appendDateNode(doc, parentNode, nodeName, date): + time = int(date[0]) * 1000 + date = str(time).split('.')[0] + appendTextNode(doc, parentNode, nodeName, date) + +def appendListNodes(doc, parentNode, name, values): + if values: + for value in values: + appendTextNode(doc, parentNode, name, value) + +def appendWrappedListNodes(doc, parentNode, wrapperName, name, values): + if values: + wrapperNode = createChildNode(doc, parentNode, wrapperName) + appendListNodes(doc, wrapperNode, name, values) + +def getId(ctx): + return str(ctx.rev()) + ':' + hex(ctx.node()[:6]) + +def appendAuthorNodes(doc, parentNode, ctx): + authorName = ctx.user() + authorMail = None + if authorName: + authorNode = createChildNode(doc, parentNode, 'author') + s = authorName.find('<') + e = authorName.find('>') + if s > 0 and e > 0: + authorMail = authorName[s + 1:e].strip() + authorName = authorName[0:s].strip() + appendTextNode(doc, authorNode, 'mail', authorMail) + appendTextNode(doc, authorNode, 'name', authorName)