diff --git a/scm-core/src/main/java/sonia/scm/repository/ChangesetViewerUtil.java b/scm-core/src/main/java/sonia/scm/repository/ChangesetViewerUtil.java
index 79da36e354..ec73339a22 100644
--- a/scm-core/src/main/java/sonia/scm/repository/ChangesetViewerUtil.java
+++ b/scm-core/src/main/java/sonia/scm/repository/ChangesetViewerUtil.java
@@ -37,7 +37,6 @@ package sonia.scm.repository;
import com.google.inject.Inject;
-import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -49,6 +48,8 @@ import sonia.scm.util.Util;
//~--- JDK imports ------------------------------------------------------------
+import java.io.IOException;
+
import java.util.Set;
/**
@@ -103,6 +104,8 @@ public class ChangesetViewerUtil extends CacheClearHook
*
* @return
*
+ *
+ * @throws IOException
* @throws NotSupportedFeatuerException
* @throws RepositoryException
*/
@@ -133,6 +136,8 @@ public class ChangesetViewerUtil extends CacheClearHook
*
* @return
*
+ *
+ * @throws IOException
* @throws NotSupportedFeatuerException
* @throws RepositoryException
*/
diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgChangesetViewer.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgChangesetViewer.java
index 587fd19594..285efa5565 100644
--- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgChangesetViewer.java
+++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgChangesetViewer.java
@@ -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 =
- "\""
- + "{rev}:{node|short}"
- + "{author|escape}"
- + "{desc|escape}"
- + "{date|isodatesec}"
- + "{tags}"
- + "{branches}"
- + "{file_adds}"
- + "{file_mods}"
- + "{file_dels}"
- + "\"";
- //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 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 getChangesets(String startRev, String endRev,
+ public ChangesetPagingResult getChangesets(String startRev, String limit,
boolean pending)
throws IOException
{
- List 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 env = new HashMap();
-
- env.put(ENV_PENDING, repositoryPath);
- command.setEnvironment(env);
- }
-
- CommandResult result = command.execute();
-
- if (result.isSuccessfull())
- {
- StringBuilder sb = new StringBuilder("");
-
- sb.append(result.getOutput()).append("");
- 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 env = new HashMap();
+
+ 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 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;
}
diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryBrowser.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryBrowser.java
index 3cda3f9952..467db78431 100644
--- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryBrowser.java
+++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryBrowser.java
@@ -50,7 +50,6 @@ import java.io.InputStream;
import java.io.OutputStream;
import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBException;
/**
*
diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java
index 03e1ff61d8..5e3117d2e4 100644
--- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java
+++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java
@@ -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;
}
diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHookEvent.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHookEvent.java
index 43f31694c5..7020f9b435 100644
--- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHookEvent.java
+++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHookEvent.java
@@ -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 ---------------------------------------------------------------
diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgUtil.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgUtil.java
index 47d5cf426b..6bdc56d72b 100644
--- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgUtil.java
+++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgUtil.java
@@ -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 extraEnv)
throws IOException
{
HgConfig config = handler.getConfig();
@@ -113,12 +112,8 @@ public class HgUtil
Map 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
*
* @return
*
* @throws IOException
*/
- public static T getResultFromScript(Class resultType, JAXBContext context,
- String scriptResource,
- HgRepositoryHandler handler,
- Repository repository, String revision,
- String path)
+ public static T getResultFromScript(Class resultType,
+ JAXBContext context, String scriptResource,
+ HgRepositoryHandler handler, File directory,
+ Map 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
+ *
+ * @return
+ *
+ * @throws IOException
+ */
+ public static T getResultFromScript(Class resultType,
+ JAXBContext context, String scriptResource,
+ HgRepositoryHandler handler, Repository repository,
+ Map 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
+ *
+ * @return
+ *
+ * @throws IOException
+ */
+ public static T getResultFromScript(Class resultType,
+ JAXBContext context, String scriptResource,
+ HgRepositoryHandler handler, Repository repository, String revision,
+ String path)
+ throws IOException
+ {
+ Map extraEnv = new HashMap();
+
+ 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;
+ }
}
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
new file mode 100644
index 0000000000..eebee94f60
--- /dev/null
+++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hglog.py
@@ -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 ''
+print ' ' + str(total) + ''
+print ' '
+
+# 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 ' '
+ print ' ' + str(i) + ':' + hex(ctx.node()[:6]) + ''
+ print ' ' + escape(ctx.user()) + ''
+ print ' ' + escape(ctx.description()) + ''
+ print ' ' + str(time).split('.')[0] + ''
+
+ # branches
+ if branch != 'default':
+ print ' '
+ print ' ' + branch + ''
+ print ' '
+
+ # tags
+ if tags:
+ print ' '
+ for t in tags:
+ print ' ' + t + ''
+ print ' '
+
+ # modifications
+ print ' '
+
+ # files added
+ if added:
+ print ' '
+ for add in added:
+ print ' ' + add + ''
+ print ' '
+
+ # files modified
+ if mods:
+ print ' '
+ for mod in mods:
+ print ' ' + mod + ''
+ print ' '
+
+ # files deleted
+ if deleted:
+ print ' '
+ for dele in deleted:
+ print ' ' + dele + ''
+ print ' '
+
+ print ' '
+ print ' '
+
+# footer
+print ' '
+print ''