From 8975eccd8880da2b50994371d2cb1ca74261dfaa Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Sat, 8 Oct 2011 15:31:10 +0200 Subject: [PATCH] improve mercurial command handling --- .../scm/repository/AbstractHgHandler.java | 402 ++++++++++++++++++ .../sonia/scm/repository/HgBlameViewer.java | 31 +- .../scm/repository/HgChangesetParser.java | 238 ----------- .../scm/repository/HgChangesetViewer.java | 127 +----- .../java/sonia/scm/repository/HgContext.java | 101 +++++ .../sonia/scm/repository/HgDiffViewer.java | 58 +-- .../scm/repository/HgRepositoryBrowser.java | 79 +--- .../scm/repository/HgRepositoryHandler.java | 26 +- .../scm/repository/HgRepositoryHookEvent.java | 16 +- .../sonia/scm/web/HgHookCallbackServlet.java | 15 +- .../java/sonia/scm/web/HgServletModule.java | 2 + .../repository/HgRepositoryHandlerTest.java | 31 +- 12 files changed, 610 insertions(+), 516 deletions(-) create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/AbstractHgHandler.java delete mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgChangesetParser.java create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgContext.java 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 new file mode 100644 index 0000000000..e36985c48f --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/AbstractHgHandler.java @@ -0,0 +1,402 @@ +/** + * 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 + * + */ + + + +package sonia.scm.repository; + +//~--- non-JDK imports -------------------------------------------------------- + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import sonia.scm.util.IOUtil; +import sonia.scm.util.Util; +import sonia.scm.web.HgUtil; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; + +/** + * + * @author Sebastian Sdorra + */ +public class AbstractHgHandler +{ + + /** Field description */ + public static final String ENV_PATH = "SCM_PATH"; + + /** Field description */ + public static final String ENV_PENDING = "HG_PENDING"; + + /** Field description */ + public static final String ENV_PYTHON_PATH = "SCM_PYTHON_PATH"; + + /** Field description */ + public static final String ENV_REPOSITORY_PATH = "SCM_REPOSITORY_PATH"; + + /** Field description */ + public static final String ENV_REVISION = "SCM_REVISION"; + + /** the logger for AbstractHgHandler */ + private static final Logger logger = + LoggerFactory.getLogger(AbstractHgHandler.class); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param handler + * @param context + * @param directory + */ + public AbstractHgHandler(HgRepositoryHandler handler, HgContext context, + File directory) + { + this(handler, null, context, directory); + } + + /** + * Constructs ... + * + * + * @param handler + * @param context + * @param repository + */ + public AbstractHgHandler(HgRepositoryHandler handler, HgContext context, + Repository repository) + { + this(handler, null, context, handler.getDirectory(repository)); + } + + /** + * Constructs ... + * + * + * @param handler + * @param jaxbContext + * @param context + * @param directory + */ + public AbstractHgHandler(HgRepositoryHandler handler, + JAXBContext jaxbContext, HgContext context, + File directory) + { + this.handler = handler; + this.jaxbContext = jaxbContext; + this.context = context; + this.directory = directory; + } + + /** + * Constructs ... + * + * + * @param handler + * @param jaxbContext + * @param context + * @param repository + */ + public AbstractHgHandler(HgRepositoryHandler handler, + JAXBContext jaxbContext, HgContext context, + Repository repository) + { + this(handler, jaxbContext, context, handler.getDirectory(repository)); + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param revision + * @param path + * + * @return + */ + protected Map createEnvironment(String revision, String path) + { + Map env = new HashMap(); + + env.put(ENV_REVISION, Util.nonNull(revision)); + env.put(ENV_PATH, Util.nonNull(path)); + + return env; + } + + /** + * Method description + * + * + * @param args + * + * @return + * + * @throws IOException + */ + protected Process createHgProcess(String... args) throws IOException + { + return createHgProcess(new HashMap(), args); + } + + /** + * Method description + * + * + * @param extraEnv + * @param args + * + * @return + * + * @throws IOException + */ + protected Process createHgProcess(Map extraEnv, + String... args) + throws IOException + { + return createProcess(extraEnv, handler.getConfig().getHgBinary(), args); + } + + /** + * Method description + * + * + * @param extraEnv + * + * @return + * + * @throws IOException + */ + protected Process createPythonProcess(Map extraEnv) + throws IOException + { + return createProcess(extraEnv, handler.getConfig().getPythonBinary()); + } + + /** + * Method description + * + * + * @return + * + * @throws IOException + */ + protected Process createPythonProcess() throws IOException + { + return createPythonProcess(new HashMap()); + } + + /** + * Method description + * + * + * @param errorStream + */ + protected void handleErrorStream(final InputStream errorStream) + { + if (errorStream != null) + { + new Thread(new Runnable() + { + @Override + public void run() + { + try + { + String content = IOUtil.getContent(errorStream); + + if (Util.isNotEmpty(content)) + { + logger.error(content.trim()); + } + } + catch (IOException ex) + { + logger.error("error during logging", ex); + } + } + }).start(); + } + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param resultType + * @param scriptResource + * @param + * + * @return + * + * @throws IOException + */ + protected T getResultFromScript(Class resultType, + String scriptResource) + throws IOException + { + return getResultFromScript(resultType, scriptResource, + new HashMap()); + } + + /** + * Method description + * + * + * @param resultType + * @param scriptResource + * @param extraEnv + * @param + * + * @return + * + * @throws IOException + */ + protected T getResultFromScript(Class resultType, + String scriptResource, Map extraEnv) + throws IOException + { + Process p = createPythonProcess(extraEnv); + T result = null; + InputStream resource = null; + InputStream input = null; + OutputStream output = null; + + try + { + resource = HgUtil.class.getResourceAsStream(scriptResource); + output = p.getOutputStream(); + IOUtil.copy(resource, output); + output.close(); + handleErrorStream(p.getErrorStream()); + input = p.getInputStream(); + result = (T) jaxbContext.createUnmarshaller().unmarshal(input); + input.close(); + } + catch (JAXBException ex) + { + logger.error("could not parse result", ex); + } + finally + { + IOUtil.close(resource); + IOUtil.close(input); + IOUtil.close(output); + } + + return result; + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param extraEnv + * @param cmd + * @param args + * + * @return + * + * @throws IOException + */ + private Process createProcess(Map extraEnv, String cmd, + String... args) + throws IOException + { + HgConfig config = handler.getConfig(); + List cmdList = new ArrayList(); + + cmdList.add(cmd); + + if (Util.isNotEmpty(args)) + { + cmdList.addAll(Arrays.asList(args)); + } + + ProcessBuilder pb = new ProcessBuilder(cmdList); + + pb.directory(directory); + + Map env = pb.environment(); + + if (context.isSystemEnvironment()) + { + env.putAll(System.getenv()); + } + + if (context.isPending()) + { + env.put(ENV_PENDING, directory.getAbsolutePath()); + } + + env.put(ENV_PYTHON_PATH, Util.nonNull(config.getPythonPath())); + env.put(ENV_REPOSITORY_PATH, directory.getAbsolutePath()); + env.putAll(extraEnv); + + return pb.start(); + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private HgContext context; + + /** Field description */ + private File directory; + + /** Field description */ + private HgRepositoryHandler handler; + + /** Field description */ + private JAXBContext jaxbContext; +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgBlameViewer.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgBlameViewer.java index 7d5e7aa95b..14e5ff3812 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgBlameViewer.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgBlameViewer.java @@ -45,13 +45,15 @@ import sonia.scm.web.HgUtil; import java.io.IOException; +import java.util.Map; + import javax.xml.bind.JAXBContext; /** * * @author Sebastian Sdorra */ -public class HgBlameViewer implements BlameViewer +public class HgBlameViewer extends AbstractHgHandler implements BlameViewer { /** Field description */ @@ -68,15 +70,15 @@ public class HgBlameViewer implements BlameViewer * * * @param handler + * @param context * @param repository * @param blameResultContext */ - public HgBlameViewer(HgRepositoryHandler handler, Repository repository, - JAXBContext blameResultContext) + public HgBlameViewer(HgRepositoryHandler handler, + JAXBContext blameResultContext, HgContext context, + Repository repository) { - this.handler = handler; - this.repository = repository; - this.blameResultContext = blameResultContext; + super(handler, blameResultContext, context, repository); } //~--- get methods ---------------------------------------------------------- @@ -103,19 +105,8 @@ public class HgBlameViewer implements BlameViewer HgUtil.getRevision(revision)); } - return HgUtil.getResultFromScript(BlameResult.class, blameResultContext, - RESOURCE_BLAME, handler, repository, - revision, path); + Map env = createEnvironment(revision, path); + + return getResultFromScript(BlameResult.class, RESOURCE_BLAME, env); } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private JAXBContext blameResultContext; - - /** Field description */ - private HgRepositoryHandler handler; - - /** Field description */ - private Repository repository; } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgChangesetParser.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgChangesetParser.java deleted file mode 100644 index eed515a139..0000000000 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgChangesetParser.java +++ /dev/null @@ -1,238 +0,0 @@ -/** - * 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 - * - */ - - - -package sonia.scm.repository; - -//~--- non-JDK imports -------------------------------------------------------- - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -import sonia.scm.util.Util; - -//~--- JDK imports ------------------------------------------------------------ - -import java.io.IOException; - -import java.text.ParseException; -import java.text.SimpleDateFormat; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.List; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -/** - * - * @author Sebastian Sdorra - */ -public class HgChangesetParser -{ - - /** the logger for HgChangesetParser */ - private static final Logger logger = - LoggerFactory.getLogger(HgChangesetParser.class); - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param in - * - * @return - * - * @throws IOException - * @throws ParserConfigurationException - * @throws SAXException - */ - public List parse(InputSource in) - throws SAXException, IOException, ParserConfigurationException - { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = factory.newDocumentBuilder(); - - return parse(builder.parse(in)); - } - - /** - * Method description - * - * - * @param document - * - * @return - */ - private List parse(Document document) - { - List changesetList = new ArrayList(); - NodeList changesetNodeList = document.getElementsByTagName("changeset"); - - if (changesetNodeList != null) - { - for (int i = 0; i < changesetNodeList.getLength(); i++) - { - Node changesetNode = changesetNodeList.item(i); - Changeset changeset = parseChangesetNode(changesetNode); - - if ((changeset != null) && changeset.isValid()) - { - changesetList.add(changeset); - } - } - } - - return changesetList; - } - - /** - * Method description - * - * - * @param changeset - * @param node - */ - private void parseChangesetChildNode(Changeset changeset, Node node) - { - String name = node.getNodeName(); - String value = node.getTextContent(); - - if (Util.isNotEmpty(value)) - { - if ("id".equals(name)) - { - changeset.setId(value); - } - else if ("author".equals(name)) - { - changeset.setAuthor(Person.toPerson(value)); - } - else if ("description".equals(name)) - { - changeset.setDescription(value); - } - else if ("date".equals(name)) - { - try - { - Date date = dateFormat.parse(value); - - changeset.setDate(date.getTime()); - } - catch (ParseException ex) - { - logger.warn("could not parse date", ex); - } - } - else if ("tags".equals(name)) - { - changeset.setTags(getList(value)); - } - else if ("branches".equals(name)) - { - changeset.setBranches(getList(value)); - } - else if ("files-added".equals(name)) - { - changeset.getModifications().setAdded(getList(value)); - } - else if ("files-mods".equals(name)) - { - changeset.getModifications().setModified(getList(value)); - } - else if ("files-dels".equals(name)) - { - changeset.getModifications().setRemoved(getList(value)); - } - } - } - - /** - * Method description - * - * - * @param changesetNode - * - * @return - */ - private Changeset parseChangesetNode(Node changesetNode) - { - Changeset changeset = new Changeset(); - NodeList childrenNodeList = changesetNode.getChildNodes(); - - if (childrenNodeList != null) - { - for (int i = 0; i < childrenNodeList.getLength(); i++) - { - Node child = childrenNodeList.item(i); - - parseChangesetChildNode(changeset, child); - } - } - - return changeset; - } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @param value - * - * @return - */ - private List getList(String value) - { - return Arrays.asList(value.split(" ")); - } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private SimpleDateFormat dateFormat = - new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); -} 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 f07d585f55..0ed2337c94 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 @@ -35,15 +35,10 @@ package sonia.scm.repository; //~--- non-JDK imports -------------------------------------------------------- -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import sonia.scm.util.Util; -import sonia.scm.web.HgUtil; //~--- JDK imports ------------------------------------------------------------ -import java.io.File; import java.io.IOException; import java.util.HashMap; @@ -55,7 +50,8 @@ import javax.xml.bind.JAXBContext; * * @author Sebastian Sdorra */ -public class HgChangesetViewer implements ChangesetViewer +public class HgChangesetViewer extends AbstractHgHandler + implements ChangesetViewer { /** Field description */ @@ -64,9 +60,6 @@ public class HgChangesetViewer implements ChangesetViewer /** Field description */ public static final String ENV_PAGE_START = "SCM_PAGE_START"; - /** Field description */ - public static final String ENV_PENDING = "HG_PENDING"; - /** Field description */ public static final String ENV_REVISION_END = "SCM_REVISION_END"; @@ -76,10 +69,6 @@ public class HgChangesetViewer implements ChangesetViewer /** Field description */ public static final String RESOURCE_LOG = "/sonia/scm/hglog.py"; - /** the logger for HgChangesetViewer */ - private static final Logger logger = - LoggerFactory.getLogger(HgChangesetViewer.class); - //~--- constructors --------------------------------------------------------- /** @@ -88,31 +77,15 @@ public class HgChangesetViewer implements ChangesetViewer * * * @param handler - * @param repositoryDirectory + * @param context * @param changesetPagingResultContext + * @param repository */ public HgChangesetViewer(HgRepositoryHandler handler, - File repositoryDirectory, - JAXBContext changesetPagingResultContext) + JAXBContext changesetPagingResultContext, + HgContext context, Repository repository) { - this.handler = handler; - this.repositoryDirectory = repositoryDirectory; - this.changesetPagingResultContext = changesetPagingResultContext; - } - - /** - * Constructs ... - * - * - * @param handler - * @param repository - * @param changesetPagingResultContext - */ - public HgChangesetViewer(HgRepositoryHandler handler, Repository repository, - JAXBContext changesetPagingResultContext) - { - this(handler, handler.getDirectory(repository), - changesetPagingResultContext); + super(handler, changesetPagingResultContext, context, repository); } //~--- get methods ---------------------------------------------------------- @@ -130,28 +103,9 @@ public class HgChangesetViewer implements ChangesetViewer @Override public ChangesetPagingResult getChangesets(int start, int max) throws IOException - { - return getChangesets(start, max, false); - } - - /** - * Method description - * - * - * @param start - * @param max - * @param pending - * - * @return - * - * @throws IOException - */ - public ChangesetPagingResult getChangesets(int start, int max, - boolean pending) - throws IOException { return getChangesets(String.valueOf(start), String.valueOf(max), null, - null, pending); + null); } /** @@ -162,58 +116,29 @@ public class HgChangesetViewer implements ChangesetViewer * @param pageLimit * @param revisionStart * @param revisionEnd - * @param pending * * @return * * @throws IOException */ public ChangesetPagingResult getChangesets(String pageStart, - String pageLimit, String revisionStart, String revisionEnd, - boolean pending) + String pageLimit, String revisionStart, String revisionEnd) throws IOException { - if (logger.isDebugEnabled()) - { - StringBuilder msg = new StringBuilder("get changesets"); - - if (pending) - { - msg.append(" (include pending)"); - } - - msg.append(" for repository ").append(repositoryDirectory.getName()); - msg.append(":"); - msg.append(" start: ").append(pageStart); - msg.append(" limit: ").append(pageLimit); - msg.append(" rev-start: ").append(revisionStart); - msg.append(" rev-limit: ").append(revisionEnd); - logger.debug(msg.toString()); - } - Map env = new HashMap(); - if (pending) - { - env.put(ENV_PENDING, repositoryDirectory.getAbsolutePath()); - } - env.put(ENV_PAGE_START, Util.nonNull(pageStart)); env.put(ENV_PAGE_LIMIT, Util.nonNull(pageLimit)); env.put(ENV_REVISION_START, Util.nonNull(revisionStart)); env.put(ENV_REVISION_END, Util.nonNull(revisionEnd)); - return HgUtil.getResultFromScript(ChangesetPagingResult.class, - changesetPagingResultContext, - RESOURCE_LOG, handler, - repositoryDirectory, env); + return getResultFromScript(ChangesetPagingResult.class, RESOURCE_LOG, env); } /** * Method description * * - * * @param startNode * @param endNode * @@ -224,36 +149,6 @@ public class HgChangesetViewer implements ChangesetViewer public ChangesetPagingResult getChangesets(String startNode, String endNode) throws IOException { - return getChangesets(startNode, endNode, false); + return getChangesets(null, null, startNode, endNode); } - - /** - * Method description - * - * - * @param startNode - * @param endNode - * @param pending - * - * @return - * - * @throws IOException - */ - public ChangesetPagingResult getChangesets(String startNode, String endNode, - boolean pending) - throws IOException - { - return getChangesets(null, null, startNode, endNode, pending); - } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private JAXBContext changesetPagingResultContext; - - /** Field description */ - private HgRepositoryHandler handler; - - /** Field description */ - private File repositoryDirectory; } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgContext.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgContext.java new file mode 100644 index 0000000000..6deac80c37 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgContext.java @@ -0,0 +1,101 @@ +/** + * 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 + * + */ + + + +package sonia.scm.repository; + +//~--- non-JDK imports -------------------------------------------------------- + +import com.google.inject.servlet.RequestScoped; + +/** + * + * @author Sebastian Sdorra + */ +@RequestScoped +public class HgContext +{ + + /** + * Method description + * + * + * @return + */ + public boolean isPending() + { + return pending; + } + + /** + * Method description + * + * + * @return + */ + public boolean isSystemEnvironment() + { + return systemEnvironment; + } + + //~--- set methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param pending + */ + public void setPending(boolean pending) + { + this.pending = pending; + } + + /** + * Method description + * + * + * @param systemEnvironment + */ + public void setSystemEnvironment(boolean systemEnvironment) + { + this.systemEnvironment = systemEnvironment; + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private boolean pending = false; + + /** Field description */ + private boolean systemEnvironment = true; +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgDiffViewer.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgDiffViewer.java index 3be23f823e..ce2f76115b 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgDiffViewer.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgDiffViewer.java @@ -35,16 +35,12 @@ package sonia.scm.repository; //~--- non-JDK imports -------------------------------------------------------- -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import sonia.scm.util.AssertUtil; import sonia.scm.util.IOUtil; import sonia.scm.util.Util; //~--- JDK imports ------------------------------------------------------------ -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -53,38 +49,21 @@ import java.io.OutputStream; * * @author Sebastian Sdorra */ -public class HgDiffViewer implements DiffViewer +public class HgDiffViewer extends AbstractHgHandler implements DiffViewer { - /** the logger for HgDiffViewer */ - private static final Logger logger = - LoggerFactory.getLogger(HgDiffViewer.class); - - //~--- constructors --------------------------------------------------------- - - /** - * Constructs ... - * - * - * @param handler - * @param repositoryDirectory - */ - public HgDiffViewer(HgRepositoryHandler handler, File repositoryDirectory) - { - this.handler = handler; - this.repositoryDirectory = repositoryDirectory; - } - /** * Constructs ... * * * @param handler + * @param context * @param repository */ - public HgDiffViewer(HgRepositoryHandler handler, Repository repository) + public HgDiffViewer(HgRepositoryHandler handler, HgContext context, + Repository repository) { - this(handler, handler.getDirectory(repository)); + super(handler, context, repository); } //~--- get methods ---------------------------------------------------------- @@ -107,27 +86,12 @@ public class HgDiffViewer implements DiffViewer AssertUtil.assertIsNotEmpty(revision); AssertUtil.assertIsNotNull(output); - ProcessBuilder builder = - new ProcessBuilder(handler.getConfig().getHgBinary(), "diff", "-c", - revision, Util.nonNull(path)); - - if (logger.isDebugEnabled()) - { - StringBuilder msg = new StringBuilder(); - - for (String param : builder.command()) - { - msg.append(param).append(" "); - } - - logger.debug(msg.toString()); - } - - Process p = builder.directory(repositoryDirectory).start(); + Process p = createHgProcess("diff", "-c", revision, Util.nonNull(path)); InputStream input = null; try { + handleErrorStream(p.getErrorStream()); input = p.getInputStream(); IOUtil.copy(input, output); } @@ -136,12 +100,4 @@ public class HgDiffViewer implements DiffViewer IOUtil.close(input); } } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private HgRepositoryHandler handler; - - /** Field description */ - 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 467db78431..f059788f5b 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 @@ -35,51 +35,31 @@ package sonia.scm.repository; //~--- non-JDK imports -------------------------------------------------------- -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import sonia.scm.util.IOUtil; import sonia.scm.util.Util; import sonia.scm.web.HgUtil; //~--- JDK imports ------------------------------------------------------------ -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.Map; + import javax.xml.bind.JAXBContext; /** * * @author Sebastian Sdorra */ -public class HgRepositoryBrowser implements RepositoryBrowser +public class HgRepositoryBrowser extends AbstractHgHandler + implements RepositoryBrowser { - /** Field description */ - public static final String DEFAULT_REVISION = "tip"; - - /** Field description */ - public static final String ENV_PATH = "SCM_PATH"; - - /** Field description */ - public static final String ENV_PYTHON_PATH = "SCM_PYTHON_PATH"; - - /** Field description */ - public static final String ENV_REPOSITORY_PATH = "SCM_REPOSITORY_PATH"; - - /** Field description */ - public static final String ENV_REVISION = "SCM_REVISION"; - /** Field description */ public static final String RESOURCE_BROWSE = "/sonia/scm/hgbrowse.py"; - /** the logger for HgRepositoryBrowser */ - private static final Logger logger = - LoggerFactory.getLogger(HgRepositoryBrowser.class); - //~--- constructors --------------------------------------------------------- /** @@ -87,16 +67,15 @@ public class HgRepositoryBrowser implements RepositoryBrowser * * * @param handler + * @param context * @param repository * @param browserResultContext */ public HgRepositoryBrowser(HgRepositoryHandler handler, - Repository repository, - JAXBContext browserResultContext) + JAXBContext browserResultContext, + HgContext context, Repository repository) { - this.handler = handler; - this.repository = repository; - this.browserResultContext = browserResultContext; + super(handler, browserResultContext, context, repository); } //~--- get methods ---------------------------------------------------------- @@ -117,33 +96,14 @@ public class HgRepositoryBrowser implements RepositoryBrowser public void getContent(String revision, String path, OutputStream output) throws IOException, RepositoryException { - if (Util.isEmpty(revision)) - { - revision = DEFAULT_REVISION; - } + revision = HgUtil.getRevision(revision); - File directory = handler.getDirectory(repository); - ProcessBuilder builder = - new ProcessBuilder(handler.getConfig().getHgBinary(), "cat", "-r", - revision, Util.nonNull(path)); - - if (logger.isDebugEnabled()) - { - StringBuilder msg = new StringBuilder(); - - for (String param : builder.command()) - { - msg.append(param).append(" "); - } - - logger.debug(msg.toString()); - } - - Process p = builder.directory(directory).start(); + Process p = createHgProcess("cat", "-r", revision, Util.nonNull(path)); InputStream input = null; try { + handleErrorStream(p.getErrorStream()); input = p.getInputStream(); IOUtil.copy(input, output); } @@ -169,19 +129,8 @@ public class HgRepositoryBrowser implements RepositoryBrowser public BrowserResult getResult(String revision, String path) throws IOException, RepositoryException { - return HgUtil.getResultFromScript(BrowserResult.class, - browserResultContext, RESOURCE_BROWSE, - handler, repository, revision, path); + Map env = createEnvironment(revision, path); + + return getResultFromScript(BrowserResult.class, RESOURCE_BROWSE, env); } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private JAXBContext browserResultContext; - - /** Field description */ - private HgRepositoryHandler handler; - - /** Field description */ - private Repository repository; } 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 af692e13fb..480216603e 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 @@ -36,6 +36,7 @@ package sonia.scm.repository; //~--- non-JDK imports -------------------------------------------------------- import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.Singleton; import org.slf4j.Logger; @@ -105,11 +106,14 @@ public class HgRepositoryHandler * * @param storeFactory * @param fileSystem + * @param hgContextProvider */ @Inject - public HgRepositoryHandler(StoreFactory storeFactory, FileSystem fileSystem) + public HgRepositoryHandler(StoreFactory storeFactory, FileSystem fileSystem, + Provider hgContextProvider) { super(storeFactory, fileSystem); + this.hgContextProvider = hgContextProvider; try { @@ -211,7 +215,8 @@ public class HgRepositoryHandler if (TYPE_NAME.equals(type)) { - blameViewer = new HgBlameViewer(this, repository, blameResultContext); + blameViewer = new HgBlameViewer(this, blameResultContext, + hgContextProvider.get(), repository); } else { @@ -242,8 +247,9 @@ public class HgRepositoryHandler if (TYPE_NAME.equals(type)) { - changesetViewer = new HgChangesetViewer(this, repository, - changesetPagingResultContext); + changesetViewer = new HgChangesetViewer(this, + changesetPagingResultContext, hgContextProvider.get(), + repository); } else { @@ -277,7 +283,7 @@ public class HgRepositoryHandler if (TYPE_NAME.equals(type)) { - diffViewer = new HgDiffViewer(this, repository); + diffViewer = new HgDiffViewer(this, hgContextProvider.get(), repository); } else { @@ -298,7 +304,8 @@ public class HgRepositoryHandler @Override public RepositoryBrowser getRepositoryBrowser(Repository repository) { - return new HgRepositoryBrowser(this, repository, browserResultContext); + return new HgRepositoryBrowser(this, browserResultContext, + hgContextProvider.get(), repository); } /** @@ -330,8 +337,8 @@ public class HgRepositoryHandler throw new IllegalStateException("directory not found"); } - return new HgChangesetViewer(this, repositoryDirectory, - changesetPagingResultContext); + return new HgChangesetViewer(this, changesetPagingResultContext, null, + null); } //~--- methods -------------------------------------------------------------- @@ -585,4 +592,7 @@ public class HgRepositoryHandler /** Field description */ private JAXBContext changesetPagingResultContext; + + /** Field description */ + private Provider hgContextProvider; } 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 7020f9b435..eb9e3bdc8b 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 @@ -96,22 +96,8 @@ public class HgRepositoryHookEvent extends AbstractRepositoryHookEvent { try { - boolean pending = type == RepositoryHookType.PRE_RECEIVE; - - if (logger.isDebugEnabled()) - { - String pendingString = ""; - - if (pending) - { - pendingString = "pending "; - } - - logger.debug("load {}changesets for hook {}", pendingString, type); - } - ChangesetPagingResult result = - createChangesetViewer().getChangesets(startRev, REV_TIP, pending); + createChangesetViewer().getChangesets(startRev, REV_TIP); if (result != null) { diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgHookCallbackServlet.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgHookCallbackServlet.java index 01c69fd8dc..62b50cb443 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgHookCallbackServlet.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgHookCallbackServlet.java @@ -36,11 +36,13 @@ package sonia.scm.web; //~--- non-JDK imports -------------------------------------------------------- import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import sonia.scm.repository.HgContext; import sonia.scm.repository.HgHookManager; import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.repository.HgRepositoryHookEvent; @@ -99,15 +101,18 @@ public class HgHookCallbackServlet extends HttpServlet * @param repositoryManager * @param handler * @param hookManager + * @param contextProvider */ @Inject public HgHookCallbackServlet(RepositoryManager repositoryManager, HgRepositoryHandler handler, - HgHookManager hookManager) + HgHookManager hookManager, + Provider contextProvider) { this.repositoryManager = repositoryManager; this.handler = handler; this.hookManager = hookManager; + this.contextProvider = contextProvider; } //~--- methods -------------------------------------------------------------- @@ -182,6 +187,11 @@ public class HgHookCallbackServlet extends HttpServlet { try { + if (type == RepositoryHookType.PRE_RECEIVE) + { + contextProvider.get().setPending(true); + } + repositoryManager.fireHookEvent(HgRepositoryHandler.TYPE_NAME, repositoryName, new HgRepositoryHookEvent(handler, @@ -260,6 +270,9 @@ public class HgHookCallbackServlet extends HttpServlet //~--- fields --------------------------------------------------------------- + /** Field description */ + private Provider contextProvider; + /** Field description */ private HgRepositoryHandler handler; diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java index 90e2ef0872..fc843aae9f 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java @@ -38,6 +38,7 @@ package sonia.scm.web; import com.google.inject.servlet.ServletModule; import sonia.scm.plugin.ext.Extension; +import sonia.scm.repository.HgContext; import sonia.scm.repository.HgHookManager; import sonia.scm.web.filter.BasicAuthenticationFilter; @@ -64,6 +65,7 @@ public class HgServletModule extends ServletModule @Override protected void configureServlets() { + bind(HgContext.class); bind(HgHookManager.class); serve(MAPPING_HOOK).with(HgHookCallbackServlet.class); diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/HgRepositoryHandlerTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/HgRepositoryHandlerTest.java index 3f265d7635..21d82f0827 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/HgRepositoryHandlerTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/HgRepositoryHandlerTest.java @@ -35,6 +35,8 @@ package sonia.scm.repository; //~--- non-JDK imports -------------------------------------------------------- +import com.google.inject.Provider; + import sonia.scm.io.DefaultFileSystem; import sonia.scm.store.StoreFactory; @@ -87,13 +89,14 @@ public class HgRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase File directory) { HgRepositoryHandler handler = new HgRepositoryHandler(factory, - new DefaultFileSystem()); + new DefaultFileSystem(), + new HgContextProvider()); handler.init(contextProvider); handler.getConfig().setRepositoryDirectory(directory); // skip tests if hg not in path - if (! handler.isConfigured()) + if (!handler.isConfigured()) { System.out.println("WARNING could not find hg, skipping test"); assumeTrue(false); @@ -101,4 +104,28 @@ public class HgRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase return handler; } + + //~--- inner classes -------------------------------------------------------- + + /** + * Dummy {@link Provider} for {@link HgContext} + * + * + * @author Sebastian Sdorra + */ + private static class HgContextProvider implements Provider + { + + /** + * Return context for mercurial + * + * + * @return context for mercurial + */ + @Override + public HgContext get() + { + return new HgContext(); + } + } }