diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/AbstractHgHandler.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/AbstractHgHandler.java index 3ba8c53a57..71c59312c4 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/AbstractHgHandler.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/AbstractHgHandler.java @@ -66,6 +66,12 @@ import javax.xml.bind.JAXBException; public class AbstractHgHandler { + /** Field description */ + public static final String ENCODING = "UTF-8"; + + /** mercurial encoding */ + public static final String ENV_HGENCODING = "HGENCODING"; + /** Field description */ public static final String ENV_NODE = "HG_NODE"; @@ -81,6 +87,9 @@ public class AbstractHgHandler /** Field description */ public static final String ENV_PENDING = "HG_PENDING"; + /** python encoding */ + public static final String ENV_PYTHONIOENCODING = "PYTHONIOENCODING"; + /** Field description */ public static final String ENV_PYTHON_PATH = "SCM_PYTHON_PATH"; @@ -432,6 +441,10 @@ public class AbstractHgHandler Map env = pb.environment(); + // force utf-8 encoding for mercurial and python + env.put(ENV_PYTHONIOENCODING, ENCODING); + env.put(ENV_HGENCODING, ENCODING); + if (context.isSystemEnvironment()) { env.putAll(System.getenv()); diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hgbrowse.py b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hgbrowse.py index ccbeb0c86f..7f305a7044 100644 --- a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hgbrowse.py +++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hgbrowse.py @@ -45,6 +45,7 @@ if len(pythonPath) > 0: from mercurial import hg, ui import datetime, time +from xml.sax.saxutils import escape def getName(path): parts = path.split('/') @@ -147,7 +148,7 @@ for file in files: print ' false' print ' ' + str(file.size()) + '' print ' ' + str(time).split('.')[0] + '' - print ' ' + desc + '' + print ' ' + escape(desc) + '' print ' ' print ' ' print '' diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hglog.py b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hglog.py index a722ab18f8..0142a6e2fc 100644 --- a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hglog.py +++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hglog.py @@ -29,7 +29,8 @@ # # -# import basic packages + +# import basic modules import sys, os # create python path @@ -40,139 +41,148 @@ if len(pythonPath) > 0: for i in range(len(pathParts)): sys.path.insert(i, pathParts[i]) -# import mercurial packages +# import mercurial modules from mercurial import hg, ui, commands from mercurial.node import hex -from xml.sax.saxutils import escape -import datetime, time +from xml.dom.minidom import Document -# header -def printHeader(total): - print '' - print '' - print ' ' + str(total) + '' - print ' ' +# util methods +def openRepository(): + repositoryPath = os.environ['SCM_REPOSITORY_PATH'] + return hg.repository(ui.ui(), path = repositoryPath) -# changeset -def printChangeset(repo, ctx): +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 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) + +# changeset methods + +def getId(ctx): + return str(ctx.rev()) + ':' + hex(ctx.node()[:6]) + +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 appendDateNode(doc, parentNode, ctx): time = int(ctx.date()[0]) * 1000 - branch = ctx.branch() - tags = ctx.tags() - status = repo.status(ctx.p1().node(), ctx.node()) - mods = status[0] - added = status[1] - deleted = status[2] + date = str(time).split('.')[0] + appendTextNode(doc, parentNode, 'date', date) + +def appendAuthorNodes(doc, parentNode, ctx): authorName = ctx.user() authorMail = None - parents = ctx.parents() - 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() - - print ' ' - print ' ' + str(ctx.rev()) + ':' + hex(ctx.node()[:6]) + '' - if parents: - for parent in parents: - print ' ' + str(parent.rev()) + ':' + hex(parent.node()[:6]) + '' - print ' ' + escape(ctx.user()) + '' - print ' ' + escape(ctx.description()) + '' - print ' ' + str(time).split('.')[0] + '' - - # author - if authorName: - print ' ' - print ' ' + authorName + '' - if authorMail: - print ' ' + authorMail + '' - print ' ' - - # branches + appendTextNode(doc, authorNode, 'mail', authorMail) + + appendTextNode(doc, authorNode, 'name', authorName) + +def appendBranchesNode(doc, parentNode, ctx): + branch = ctx.branch() if branch != 'default': - print ' ' + branch + '' - - # tags - if tags: - for t in tags: - print ' ' + t + '' + appendTextNode(doc, parentNode, 'branches', branch) - # modifications - print ' ' +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]) - # files added - if added: - print ' ' - for add in added: - print ' ' + add + '' - print ' ' +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, ctx) + appendAuthorNodes(doc, changesetNode, ctx) + appendBranchesNode(doc, changesetNode, ctx) + appendListNodes(doc, changesetNode, 'tags', ctx.tags()) + appendModifications(doc, changesetNode, ctx) + +# changeset methods end - # files modified - if mods: - print ' ' - for mod in mods: - print ' ' + mod + '' - print ' ' +# change log methods - # files deleted - if deleted: - print ' ' - for dele in deleted: - print ' ' + dele + '' - print ' ' - - print ' ' - print ' ' - -# footer -def printFooter(): - print ' ' - print '' - -def printChangesetsForPath(repo, rev, path): +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() - - total = len(revs) - # 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 - printHeader(total) + changesets = createBasicNodes(doc, revs) for ctx in revs: - printChangeset(repo, ctx) - printFooter() + appendChangesetNode(doc, changesets, ctx) -def printChangesetsForStartAndEnd(repo, startRev, endRev): - printHeader(len(repo)) +def appendChangesetsForStartAndEnd(doc, repo, startRev, endRev): + changesets = createBasicNodes(doc, repo) for i in range(endRev, startRev, -1): - printChangeset(repo, repo[i]) - printFooter() + appendChangesetNode(doc, changesets, repo[i]) + +# change log methods + +# main method -repositoryPath = os.environ['SCM_REPOSITORY_PATH'] -repo = hg.repository(ui.ui(), path = repositoryPath) +repo = openRepository() +doc = Document() path = os.environ['SCM_PATH'] startNode = os.environ['SCM_REVISION_START'] @@ -180,11 +190,10 @@ endNode = os.environ['SCM_REVISION_END'] rev = os.environ['SCM_REVISION'] if len(path) > 0: - printChangesetsForPath(repo, rev, path) + appendChangesetsForPath(doc, repo, rev, path) elif len(rev) > 0: ctx = repo[rev] - print '' - printChangeset(repo, ctx) + appendChangesetNode(doc, doc, ctx) else: if len(startNode) > 0 and len(endNode) > 0: # start and end revision @@ -194,18 +203,15 @@ 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 - printChangesetsForStartAndEnd(repo, startRev, endRev) - + appendChangesetsForStartAndEnd(doc, repo, startRev, endRev) + +# write document +writeXml(doc)