mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-10 07:25:44 +01:00
improve performance of mercurial changesetviewer
This commit is contained in:
@@ -38,25 +38,18 @@ package sonia.scm.repository;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import sonia.scm.io.Command;
|
||||
import sonia.scm.io.CommandResult;
|
||||
import sonia.scm.io.SimpleCommand;
|
||||
import sonia.scm.util.IOUtil;
|
||||
import sonia.scm.util.AssertUtil;
|
||||
import sonia.scm.web.HgUtil;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.bind.JAXBContext;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -65,30 +58,17 @@ import javax.xml.parsers.ParserConfigurationException;
|
||||
public class HgChangesetViewer implements ChangesetViewer
|
||||
{
|
||||
|
||||
/** Field description */
|
||||
public static final String ID_TIP = "tip";
|
||||
|
||||
/** Field description */
|
||||
//J-
|
||||
public static final String TEMPLATE_CHANGESETS =
|
||||
"\"<changeset>"
|
||||
+ "<id>{rev}:{node|short}</id>"
|
||||
+ "<author>{author|escape}</author>"
|
||||
+ "<description>{desc|escape}</description>"
|
||||
+ "<date>{date|isodatesec}</date>"
|
||||
+ "<tags>{tags}</tags>"
|
||||
+ "<branches>{branches}</branches>"
|
||||
+ "<files-added>{file_adds}</files-added>"
|
||||
+ "<files-mods>{file_mods}</files-mods>"
|
||||
+ "<files-dels>{file_dels}</files-dels>"
|
||||
+ "</changeset>\"";
|
||||
//J+
|
||||
|
||||
/** Field description */
|
||||
public static final String ENV_PENDING = "HG_PENDING";
|
||||
|
||||
/** Field description */
|
||||
public static final String TEMPLATE_TOTAL = "{rev}";
|
||||
public static final String ENV_REVISION_LIMIT = "SCM_REVISION_LIMIT";
|
||||
|
||||
/** Field description */
|
||||
public static final String ENV_REVISION_START = "SCM_REVISION_START";
|
||||
|
||||
/** Field description */
|
||||
public static final String RESOURCE_LOG = "/sonia/scm/hglog.py";
|
||||
|
||||
/** the logger for HgChangesetViewer */
|
||||
private static final Logger logger =
|
||||
@@ -102,11 +82,16 @@ public class HgChangesetViewer implements ChangesetViewer
|
||||
*
|
||||
*
|
||||
* @param handler
|
||||
* @param repository
|
||||
* @param repositoryDirectory
|
||||
* @param changesetPagingResultContext
|
||||
*/
|
||||
public HgChangesetViewer(HgRepositoryHandler handler, Repository repository)
|
||||
public HgChangesetViewer(HgRepositoryHandler handler,
|
||||
File repositoryDirectory,
|
||||
JAXBContext changesetPagingResultContext)
|
||||
{
|
||||
this(handler, handler.getDirectory(repository).getAbsolutePath());
|
||||
this.handler = handler;
|
||||
this.repositoryDirectory = repositoryDirectory;
|
||||
this.changesetPagingResultContext = changesetPagingResultContext;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,12 +99,14 @@ public class HgChangesetViewer implements ChangesetViewer
|
||||
*
|
||||
*
|
||||
* @param handler
|
||||
* @param repositoryPath
|
||||
* @param repository
|
||||
* @param changesetPagingResultContext
|
||||
*/
|
||||
public HgChangesetViewer(HgRepositoryHandler handler, String repositoryPath)
|
||||
public HgChangesetViewer(HgRepositoryHandler handler, Repository repository,
|
||||
JAXBContext changesetPagingResultContext)
|
||||
{
|
||||
this.handler = handler;
|
||||
this.repositoryPath = repositoryPath;
|
||||
this(handler, handler.getDirectory(repository),
|
||||
changesetPagingResultContext);
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
@@ -131,51 +118,14 @@ public class HgChangesetViewer implements ChangesetViewer
|
||||
* @param max
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public ChangesetPagingResult getChangesets(int start, int max)
|
||||
throws IOException
|
||||
{
|
||||
ChangesetPagingResult changesets = null;
|
||||
InputStream in = null;
|
||||
|
||||
try
|
||||
{
|
||||
int total = getTotalChangesets(repositoryPath);
|
||||
int startRev = total - start;
|
||||
int endRev = total - start - (max - 1);
|
||||
|
||||
if (endRev < 0)
|
||||
{
|
||||
endRev = 0;
|
||||
}
|
||||
|
||||
List<Changeset> changesetList = getChangesets(Integer.toString(startRev),
|
||||
Integer.toString(endRev));
|
||||
|
||||
if (changesetList != null)
|
||||
{
|
||||
if (total == -1)
|
||||
{
|
||||
total = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
total++;
|
||||
}
|
||||
|
||||
changesets = new ChangesetPagingResult(total, changesetList);
|
||||
}
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
logger.error("could not load changesets", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtil.close(in);
|
||||
}
|
||||
|
||||
return changesets;
|
||||
return getChangesets(String.valueOf(start), String.valueOf(max), false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -183,66 +133,41 @@ public class HgChangesetViewer implements ChangesetViewer
|
||||
*
|
||||
*
|
||||
* @param startRev
|
||||
* @param endRev
|
||||
* @param limit
|
||||
* @param pending
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public List<Changeset> getChangesets(String startRev, String endRev,
|
||||
public ChangesetPagingResult getChangesets(String startRev, String limit,
|
||||
boolean pending)
|
||||
throws IOException
|
||||
{
|
||||
List<Changeset> changesetList = null;
|
||||
InputStream in = null;
|
||||
AssertUtil.assertIsNotEmpty(startRev);
|
||||
AssertUtil.assertIsNotEmpty(limit);
|
||||
|
||||
try
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
SimpleCommand command =
|
||||
new SimpleCommand(handler.getConfig().getHgBinary(), "-R",
|
||||
repositoryPath, "log", "-r", startRev + ":" + endRev,
|
||||
"--template", TEMPLATE_CHANGESETS);
|
||||
|
||||
if (pending)
|
||||
{
|
||||
Map<String, String> env = new HashMap<String, String>();
|
||||
|
||||
env.put(ENV_PENDING, repositoryPath);
|
||||
command.setEnvironment(env);
|
||||
}
|
||||
|
||||
CommandResult result = command.execute();
|
||||
|
||||
if (result.isSuccessfull())
|
||||
{
|
||||
StringBuilder sb = new StringBuilder("<changesets>");
|
||||
|
||||
sb.append(result.getOutput()).append("</changesets>");
|
||||
changesetList = new HgChangesetParser().parse(
|
||||
new InputSource(new StringReader(sb.toString())));
|
||||
}
|
||||
else if (logger.isErrorEnabled())
|
||||
{
|
||||
logger.error(
|
||||
"command for fetching changesets failed with exit code {} and output {}",
|
||||
result.getReturnCode(), result.getOutput());
|
||||
}
|
||||
}
|
||||
catch (ParserConfigurationException ex)
|
||||
{
|
||||
logger.error("could not parse changesets", ex);
|
||||
}
|
||||
catch (SAXException ex)
|
||||
{
|
||||
logger.error("could not unmarshall changesets", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtil.close(in);
|
||||
logger.debug("get changesets for repository {}, start: {}, limit: {}",
|
||||
new Object[] { repositoryDirectory.getName(),
|
||||
startRev, limit });
|
||||
}
|
||||
|
||||
return changesetList;
|
||||
Map<String, String> env = new HashMap<String, String>();
|
||||
|
||||
if (pending)
|
||||
{
|
||||
env.put(ENV_PENDING, repositoryDirectory.getAbsolutePath());
|
||||
}
|
||||
|
||||
env.put(ENV_REVISION_START, startRev);
|
||||
env.put(ENV_REVISION_LIMIT, limit);
|
||||
|
||||
return HgUtil.getResultFromScript(ChangesetPagingResult.class,
|
||||
changesetPagingResultContext,
|
||||
RESOURCE_LOG, handler,
|
||||
repositoryDirectory, env);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -250,55 +175,26 @@ public class HgChangesetViewer implements ChangesetViewer
|
||||
*
|
||||
*
|
||||
* @param startRev
|
||||
* @param endRev
|
||||
* @param limit
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public List<Changeset> getChangesets(String startRev, String endRev)
|
||||
public ChangesetPagingResult getChangesets(String startRev, String limit)
|
||||
throws IOException
|
||||
{
|
||||
return getChangesets(startRev, endRev, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param repositoryPath
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private int getTotalChangesets(String repositoryPath) throws IOException
|
||||
{
|
||||
int total = -1;
|
||||
Command command = new SimpleCommand(handler.getConfig().getHgBinary(),
|
||||
"-R", repositoryPath, "tip", "--template",
|
||||
TEMPLATE_TOTAL);
|
||||
CommandResult result = command.execute();
|
||||
|
||||
if (result.isSuccessfull())
|
||||
{
|
||||
total = Integer.parseInt(result.getOutput().trim());
|
||||
}
|
||||
else if (logger.isErrorEnabled())
|
||||
{
|
||||
logger.error(
|
||||
"could not read tip revision, command returned with exit code {} and content {}",
|
||||
result.getReturnCode(), result.getOutput());
|
||||
}
|
||||
|
||||
return total;
|
||||
return getChangesets(startRev, limit, false);
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private JAXBContext changesetPagingResultContext;
|
||||
|
||||
/** Field description */
|
||||
private HgRepositoryHandler handler;
|
||||
|
||||
/** Field description */
|
||||
private String repositoryPath;
|
||||
private File repositoryDirectory;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,6 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBException;
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
@@ -115,6 +115,8 @@ public class HgRepositoryHandler
|
||||
{
|
||||
this.browserResultContext = JAXBContext.newInstance(BrowserResult.class);
|
||||
this.blameResultContext = JAXBContext.newInstance(BlameResult.class);
|
||||
this.changesetPagingResultContext =
|
||||
JAXBContext.newInstance(ChangesetPagingResult.class);
|
||||
}
|
||||
catch (JAXBException ex)
|
||||
{
|
||||
@@ -240,7 +242,8 @@ public class HgRepositoryHandler
|
||||
|
||||
if (TYPE_NAME.equals(type))
|
||||
{
|
||||
changesetViewer = new HgChangesetViewer(this, repository);
|
||||
changesetViewer = new HgChangesetViewer(this, repository,
|
||||
changesetPagingResultContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -310,6 +313,27 @@ public class HgRepositoryHandler
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param repositoryDirectory
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
HgChangesetViewer getChangesetViewer(File repositoryDirectory)
|
||||
{
|
||||
AssertUtil.assertIsNotNull(repositoryDirectory);
|
||||
|
||||
if (!repositoryDirectory.isDirectory())
|
||||
{
|
||||
throw new IllegalStateException("directory not found");
|
||||
}
|
||||
|
||||
return new HgChangesetViewer(this, repositoryDirectory,
|
||||
changesetPagingResultContext);
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -552,4 +576,7 @@ public class HgRepositoryHandler
|
||||
|
||||
/** Field description */
|
||||
private JAXBContext browserResultContext;
|
||||
|
||||
/** Field description */
|
||||
private JAXBContext changesetPagingResultContext;
|
||||
}
|
||||
|
||||
@@ -110,8 +110,13 @@ public class HgRepositoryHookEvent extends AbstractRepositoryHookEvent
|
||||
logger.debug("load {}changesets for hook {}", pendingString, type);
|
||||
}
|
||||
|
||||
changesets = createChangesetViewer().getChangesets(startRev, REV_TIP,
|
||||
pending);
|
||||
ChangesetPagingResult result =
|
||||
createChangesetViewer().getChangesets(startRev, REV_TIP, pending);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
changesets = result.getChangesets();
|
||||
}
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
@@ -147,8 +152,7 @@ public class HgRepositoryHookEvent extends AbstractRepositoryHookEvent
|
||||
File directory = handler.getConfig().getRepositoryDirectory();
|
||||
File repositoryDirectory = new File(directory, repositoryName);
|
||||
|
||||
return new HgChangesetViewer(handler,
|
||||
repositoryDirectory.getAbsolutePath());
|
||||
return handler.getChangesetViewer(repositoryDirectory);
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
@@ -39,7 +39,6 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import sonia.scm.SCMContext;
|
||||
import sonia.scm.repository.BrowserResult;
|
||||
import sonia.scm.repository.HgConfig;
|
||||
import sonia.scm.repository.HgRepositoryHandler;
|
||||
import sonia.scm.repository.Repository;
|
||||
@@ -53,6 +52,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
@@ -96,16 +96,15 @@ public class HgUtil
|
||||
*
|
||||
*
|
||||
* @param handler
|
||||
* @param repository
|
||||
* @param revision
|
||||
* @param path
|
||||
* @param directory
|
||||
* @param extraEnv
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public static Process createPythonProcess(HgRepositoryHandler handler,
|
||||
Repository repository, String revision, String path)
|
||||
File directory, Map<String, String> extraEnv)
|
||||
throws IOException
|
||||
{
|
||||
HgConfig config = handler.getConfig();
|
||||
@@ -113,12 +112,8 @@ public class HgUtil
|
||||
Map<String, String> env = pb.environment();
|
||||
|
||||
env.put(ENV_PYTHON_PATH, Util.nonNull(config.getPythonPath()));
|
||||
|
||||
String directory = handler.getDirectory(repository).getAbsolutePath();
|
||||
|
||||
env.put(ENV_REPOSITORY_PATH, directory);
|
||||
env.put(ENV_REVISION, getRevision(revision));
|
||||
env.put(ENV_PATH, Util.nonNull(path));
|
||||
env.put(ENV_REPOSITORY_PATH, directory.getAbsolutePath());
|
||||
env.putAll(extraEnv);
|
||||
|
||||
return pb.start();
|
||||
}
|
||||
@@ -145,21 +140,6 @@ public class HgUtil
|
||||
return new File(cgiDirectory, CGI_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param revision
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static String getRevision(String revision)
|
||||
{
|
||||
return Util.isEmpty(revision)
|
||||
? REVISION_TIP
|
||||
: revision;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
@@ -168,23 +148,21 @@ public class HgUtil
|
||||
* @param context
|
||||
* @param scriptResource
|
||||
* @param handler
|
||||
* @param repository
|
||||
* @param revision
|
||||
* @param path
|
||||
* @param directory
|
||||
* @param extraEnv
|
||||
* @param <T>
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public static <T> T getResultFromScript(Class<T> resultType, JAXBContext context,
|
||||
String scriptResource,
|
||||
HgRepositoryHandler handler,
|
||||
Repository repository, String revision,
|
||||
String path)
|
||||
public static <T> T getResultFromScript(Class<T> resultType,
|
||||
JAXBContext context, String scriptResource,
|
||||
HgRepositoryHandler handler, File directory,
|
||||
Map<String, String> extraEnv)
|
||||
throws IOException
|
||||
{
|
||||
Process p = createPythonProcess(handler, repository, revision, path);
|
||||
Process p = createPythonProcess(handler, directory, extraEnv);
|
||||
T result = null;
|
||||
InputStream resource = null;
|
||||
InputStream input = null;
|
||||
@@ -213,4 +191,79 @@ public class HgUtil
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param resultType
|
||||
* @param context
|
||||
* @param scriptResource
|
||||
* @param handler
|
||||
* @param repository
|
||||
* @param extraEnv
|
||||
* @param <T>
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public static <T> T getResultFromScript(Class<T> resultType,
|
||||
JAXBContext context, String scriptResource,
|
||||
HgRepositoryHandler handler, Repository repository,
|
||||
Map<String, String> extraEnv)
|
||||
throws IOException
|
||||
{
|
||||
File directory = handler.getDirectory(repository);
|
||||
|
||||
return getResultFromScript(resultType, context, scriptResource, handler,
|
||||
directory, extraEnv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param resultType
|
||||
* @param context
|
||||
* @param scriptResource
|
||||
* @param handler
|
||||
* @param repository
|
||||
* @param revision
|
||||
* @param path
|
||||
* @param <T>
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public static <T> T getResultFromScript(Class<T> resultType,
|
||||
JAXBContext context, String scriptResource,
|
||||
HgRepositoryHandler handler, Repository repository, String revision,
|
||||
String path)
|
||||
throws IOException
|
||||
{
|
||||
Map<String, String> extraEnv = new HashMap<String, String>();
|
||||
|
||||
extraEnv.put(ENV_REVISION, getRevision(revision));
|
||||
extraEnv.put(ENV_PATH, Util.nonNull(path));
|
||||
|
||||
return getResultFromScript(resultType, context, scriptResource, handler,
|
||||
repository, extraEnv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param revision
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static String getRevision(String revision)
|
||||
{
|
||||
return Util.isEmpty(revision)
|
||||
? REVISION_TIP
|
||||
: revision;
|
||||
}
|
||||
}
|
||||
|
||||
131
scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hglog.py
Normal file
131
scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hglog.py
Normal file
@@ -0,0 +1,131 @@
|
||||
#
|
||||
# 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 sys, os
|
||||
|
||||
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])
|
||||
|
||||
from mercurial import hg, ui, commands
|
||||
from mercurial.node import hex
|
||||
from xml.sax.saxutils import escape
|
||||
import datetime, time
|
||||
|
||||
repositoryPath = os.environ['SCM_REPOSITORY_PATH']
|
||||
repo = hg.repository(ui.ui(), path = repositoryPath)
|
||||
|
||||
start = os.environ['SCM_REVISION_START']
|
||||
limit = os.environ['SCM_REVISION_LIMIT']
|
||||
|
||||
total = len(repo)
|
||||
limit = int(limit)
|
||||
|
||||
try:
|
||||
start = int(start)
|
||||
startRev = total - start - 1
|
||||
if startRev < 0:
|
||||
startRev = 0
|
||||
except ValueError:
|
||||
startRev = repo[start].rev()
|
||||
|
||||
endRev = startRev - limit
|
||||
if endRev < -1:
|
||||
endRev = -1
|
||||
|
||||
# header
|
||||
print '<changeset-paging>'
|
||||
print ' <total>' + str(total) + '</total>'
|
||||
print ' <changesets>'
|
||||
|
||||
# changesets
|
||||
for i in range(startRev, endRev, -1):
|
||||
ctx = repo[i]
|
||||
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]
|
||||
|
||||
print ' <changeset>'
|
||||
print ' <id>' + str(i) + ':' + hex(ctx.node()[:6]) + '</id>'
|
||||
print ' <author>' + escape(ctx.user()) + '</author>'
|
||||
print ' <description>' + escape(ctx.description()) + '</description>'
|
||||
print ' <date>' + str(time).split('.')[0] + '</date>'
|
||||
|
||||
# branches
|
||||
if branch != 'default':
|
||||
print ' <branches>'
|
||||
print ' <branch>' + branch + '</branch>'
|
||||
print ' </branches>'
|
||||
|
||||
# tags
|
||||
if tags:
|
||||
print ' <tags>'
|
||||
for t in tags:
|
||||
print ' <tag>' + t + '</tag>'
|
||||
print ' </tags>'
|
||||
|
||||
# modifications
|
||||
print ' <modifications>'
|
||||
|
||||
# files added
|
||||
if added:
|
||||
print ' <added>'
|
||||
for add in added:
|
||||
print ' <file>' + add + '</file>'
|
||||
print ' </added>'
|
||||
|
||||
# files modified
|
||||
if mods:
|
||||
print ' <modified>'
|
||||
for mod in mods:
|
||||
print ' <file>' + mod + '</file>'
|
||||
print ' </modified>'
|
||||
|
||||
# files deleted
|
||||
if deleted:
|
||||
print ' <deleted>'
|
||||
for dele in deleted:
|
||||
print ' <file>' + dele + '</file>'
|
||||
print ' </deleted>'
|
||||
|
||||
print ' </modifications>'
|
||||
print ' </changeset>'
|
||||
|
||||
# footer
|
||||
print ' </changesets>'
|
||||
print '</changeset-paging>'
|
||||
Reference in New Issue
Block a user