From 20b62974f4e4deb880a2173ee00903b633baad93 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Sun, 24 Jul 2011 13:36:19 +0200 Subject: [PATCH] improve creation of mercurial hook script --- .../sonia/scm/repository/HgHookManager.java | 138 +++++++++++ .../main/java/sonia/scm/web/HgCGIServlet.java | 12 +- .../sonia/scm/web/HgHookScriptFilter.java | 214 ------------------ .../java/sonia/scm/web/HgServletModule.java | 6 - .../src/main/resources/sonia/scm/hghook.py | 11 +- 5 files changed, 149 insertions(+), 232 deletions(-) delete mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgHookScriptFilter.java diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgHookManager.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgHookManager.java index 1f53c98f8f..2a3047bf06 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgHookManager.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgHookManager.java @@ -35,12 +35,30 @@ package sonia.scm.repository; //~--- non-JDK imports -------------------------------------------------------- +import com.google.inject.Inject; import com.google.inject.Singleton; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import sonia.scm.SCMContextProvider; +import sonia.scm.io.RegexResourceProcessor; +import sonia.scm.io.ResourceProcessor; +import sonia.scm.util.IOUtil; +import sonia.scm.web.HgWebConfigWriter; + //~--- JDK imports ------------------------------------------------------------ +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + import java.util.UUID; +import javax.servlet.http.HttpServletRequest; + /** * * @author Sebastian Sdorra @@ -49,6 +67,71 @@ import java.util.UUID; public class HgHookManager { + /** Field description */ + public static final String SCRIPT_TEMPLATE = "/sonia/scm/hghook.py"; + + /** the logger for HgHookManager */ + private static final Logger logger = + LoggerFactory.getLogger(HgHookManager.class); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param context + */ + @Inject + public HgHookManager(SCMContextProvider context) + { + this.context = context; + } + + //~--- methods -------------------------------------------------------------- + + /** + * TODO check if file exists + * + * + * @param request + * + * @throws IOException + */ + public void writeHookScript(HttpServletRequest request) throws IOException + { + if (isScriptWriteAble()) + { + synchronized (this) + { + if (isScriptWriteAble()) + { + StringBuilder url = new StringBuilder(request.getScheme()); + + url.append("://localhost:").append(request.getServerPort()); + url.append(request.getContextPath()).append("/api/rest/hook/hg/"); + + if (hgHookScript == null) + { + File cgiDirectory = new File(context.getBaseDirectory(), "cgi-bin"); + + IOUtil.mkdirs(cgiDirectory); + hgHookScript = new File(cgiDirectory, "scmhooks.py"); + } + + if (logger.isDebugEnabled()) + { + logger.debug("write hg hook script to '{}'", hgHookScript); + } + + writeScript(hgHookScript, url.toString()); + } + } + } + } + + //~--- get methods ---------------------------------------------------------- + /** * Method description * @@ -73,8 +156,63 @@ public class HgHookManager return challenge.equals(challenge); } + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * + * @param script + * @param url + * + * @throws IOException + */ + private void writeScript(File script, String url) throws IOException + { + InputStream input = null; + OutputStream output = null; + + try + { + input = HgWebConfigWriter.class.getResourceAsStream(SCRIPT_TEMPLATE); + output = new FileOutputStream(script); + + ResourceProcessor rp = new RegexResourceProcessor(); + + rp.addVariable("url", url); + rp.addVariable("challenge", getChallenge()); + rp.process(input, output); + script.setExecutable(true); + } + finally + { + IOUtil.close(input); + IOUtil.close(output); + } + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + private boolean isScriptWriteAble() + { + return (hgHookScript == null) ||!hgHookScript.exists(); + } + //~--- fields --------------------------------------------------------------- /** Field description */ private String challenge = UUID.randomUUID().toString(); + + /** Field description */ + private SCMContextProvider context; + + /** Field description */ + private volatile File hgHookScript; } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java index 4fd8eb82b2..0c08fb9e9a 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java @@ -40,6 +40,7 @@ import com.google.inject.Singleton; import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.HgConfig; +import sonia.scm.repository.HgHookManager; import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryManager; @@ -97,17 +98,19 @@ public class HgCGIServlet extends HttpServlet * @param configuration * @param repositoryManager * @param handler + * @param hookManager */ @Inject public HgCGIServlet(CGIExecutorFactory cgiExecutorFactory, ScmConfiguration configuration, RepositoryManager repositoryManager, - HgRepositoryHandler handler) + HgRepositoryHandler handler, HgHookManager hookManager) { this.cgiExecutorFactory = cgiExecutorFactory; this.configuration = configuration; this.repositoryManager = repositoryManager; this.handler = handler; + this.hookManager = hookManager; } //~--- methods -------------------------------------------------------------- @@ -146,7 +149,7 @@ public class HgCGIServlet extends HttpServlet { throw new ServletException("repository not found"); } - + String name = repository.getName(); File directory = handler.getDirectory(repository); String pythonPath = ""; @@ -162,6 +165,8 @@ public class HgCGIServlet extends HttpServlet } } + hookManager.writeHookScript(request); + CGIExecutor executor = cgiExecutorFactory.createExecutor(configuration, getServletContext(), request, response); @@ -258,6 +263,9 @@ public class HgCGIServlet extends HttpServlet /** Field description */ private HgRepositoryHandler handler; + /** Field description */ + private HgHookManager hookManager; + /** Field description */ private RepositoryManager repositoryManager; } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgHookScriptFilter.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgHookScriptFilter.java deleted file mode 100644 index e340e1a952..0000000000 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgHookScriptFilter.java +++ /dev/null @@ -1,214 +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.web; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.google.inject.Inject; -import com.google.inject.Singleton; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import sonia.scm.SCMContextProvider; -import sonia.scm.io.RegexResourceProcessor; -import sonia.scm.io.ResourceProcessor; -import sonia.scm.repository.HgConfig; -import sonia.scm.repository.HgHookManager; -import sonia.scm.repository.HgRepositoryHandler; -import sonia.scm.util.IOUtil; -import sonia.scm.util.Util; -import sonia.scm.web.filter.HttpFilter; - -//~--- JDK imports ------------------------------------------------------------ - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * - * @author Sebastian Sdorra - */ -@Singleton -public class HgHookScriptFilter extends HttpFilter -{ - - /** Field description */ - public static final String SCRIPT_TEMPLATE = "/sonia/scm/hghook.py"; - - /** the logger for HgHookScriptFilter */ - private static final Logger logger = - LoggerFactory.getLogger(HgHookScriptFilter.class); - - //~--- constructors --------------------------------------------------------- - - /** - * Constructs ... - * - * - * @param context - * @param handler - * @param hookManager - */ - @Inject - public HgHookScriptFilter(SCMContextProvider context, - HgRepositoryHandler handler, - HgHookManager hookManager) - { - this.context = context; - this.handler = handler; - this.hookManager = hookManager; - } - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param request - * @param response - * @param chain - * - * @throws IOException - * @throws ServletException - */ - @Override - protected void doFilter(HttpServletRequest request, - HttpServletResponse response, FilterChain chain) - throws IOException, ServletException - { - if (!written) - { - synchronized (HgHookScriptFilter.class) - { - if (!written) - { - writeHookScript(request); - written = true; - } - } - } - - chain.doFilter(request, response); - } - - /** - * Method description - * - * - * @param request - * - * @throws IOException - */ - private void writeHookScript(HttpServletRequest request) throws IOException - { - StringBuilder url = new StringBuilder(request.getScheme()); - - url.append("://localhost:").append(request.getServerPort()); - url.append(request.getContextPath()).append("/api/rest/hook/hg/"); - - File cgiDirectory = new File(context.getBaseDirectory(), "cgi-bin"); - - IOUtil.mkdirs(cgiDirectory); - - File hgHookScript = new File(cgiDirectory, "scmhooks.py"); - - if (logger.isDebugEnabled()) - { - logger.debug("write hg hook script to '{}'", hgHookScript); - } - - writeScript(hgHookScript, url.toString()); - } - - /** - * Method description - * - * - * - * @param script - * @param url - * - * @throws IOException - */ - private void writeScript(File script, String url) throws IOException - { - InputStream input = null; - OutputStream output = null; - - try - { - input = HgWebConfigWriter.class.getResourceAsStream(SCRIPT_TEMPLATE); - output = new FileOutputStream(script); - - HgConfig config = handler.getConfig(); - ResourceProcessor rp = new RegexResourceProcessor(); - - rp.addVariable("python", config.getPythonBinary()); - rp.addVariable("path", Util.nonNull(config.getPythonPath())); - rp.addVariable("url", url); - rp.addVariable("challenge", hookManager.getChallenge()); - rp.process(input, output); - script.setExecutable(true); - } - finally - { - IOUtil.close(input); - IOUtil.close(output); - } - } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private SCMContextProvider context; - - /** Field description */ - private HgRepositoryHandler handler; - - /** Field description */ - private HgHookManager hookManager; - - /** Field description */ - private volatile boolean written = false; -} 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 1c003eb6b9..6e405aa405 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 @@ -49,9 +49,6 @@ import sonia.scm.web.filter.BasicAuthenticationFilter; public class HgServletModule extends ServletModule { - /** Field description */ - public static final String MAPPING_ALL = "/*"; - /** Field description */ public static final String MAPPING_HG = "/hg/*"; @@ -66,9 +63,6 @@ public class HgServletModule extends ServletModule { bind(HgHookManager.class); - // write hook script - filter(MAPPING_ALL).through(HgHookScriptFilter.class); - // register hg cgi servlet filter(MAPPING_HG).through(BasicAuthenticationFilter.class); filter(MAPPING_HG).through(HgPermissionFilter.class); diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hghook.py b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hghook.py index 7e45c39298..d1507ae32c 100644 --- a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hghook.py +++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hghook.py @@ -1,5 +1,3 @@ -#!/usr/bin/env ${python} - # # registration .hg/hgrc: # @@ -7,14 +5,7 @@ # changegroup.scm = python:scmhooks.callback # -import os, sys, urllib - -pythonPath = "${path}" - -if len(pythonPath) > 0: - pathParts = pythonPath.split(os.pathsep) - for i in range(len(pathParts)): - sys.path.insert(i, pathParts[i]) +import os, urllib baseUrl = "${url}" challenge = "${challenge}"