diff --git a/plugins/scm-git-plugin/pom.xml b/plugins/scm-git-plugin/pom.xml index 03059db1bd..1f90d6868c 100644 --- a/plugins/scm-git-plugin/pom.xml +++ b/plugins/scm-git-plugin/pom.xml @@ -17,6 +17,12 @@ + + sonia.scm + scm-web-api + 1.0-SNAPSHOT + + javax.servlet servlet-api @@ -25,11 +31,28 @@ - sonia.scm - scm-web-api - 1.0-SNAPSHOT + org.eclipse.jgit + org.eclipse.jgit + ${jgit.version} + + + + org.eclipse.jgit + org.eclipse.jgit.http.server + ${jgit.version} + + 0.9.3 + + + + + jgit-repository + http://download.eclipse.org/jgit/maven + + + diff --git a/plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitConfig.java b/plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitConfig.java index 4563679d1a..9f508effe6 100644 --- a/plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitConfig.java +++ b/plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitConfig.java @@ -29,6 +29,8 @@ * */ + + package sonia.scm.repository; //~--- JDK imports ------------------------------------------------------------ @@ -40,60 +42,4 @@ import javax.xml.bind.annotation.XmlRootElement; * @author Sebastian Sdorra */ @XmlRootElement(name = "config") -public class GitConfig extends SimpleRepositoryConfig -{ - - /** - * Method description - * - * - * @return - */ - public String getGitBinary() - { - return gitBinary; - } - - /** - * Method description - * - * - * @return - */ - public String getGitHttpBackend() - { - return gitHttpBackend; - } - - //~--- set methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @param gitBinary - */ - public void setGitBinary(String gitBinary) - { - this.gitBinary = gitBinary; - } - - /** - * Method description - * - * - * @param gitHttpBackend - */ - public void setGitHttpBackend(String gitHttpBackend) - { - this.gitHttpBackend = gitHttpBackend; - } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private String gitBinary = "git"; - - /** Field description */ - private String gitHttpBackend = "git-http-backend"; -} +public class GitConfig extends SimpleRepositoryConfig {} diff --git a/plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryHandler.java b/plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryHandler.java index fb3a4008c3..91e149ffe5 100644 --- a/plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryHandler.java +++ b/plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryHandler.java @@ -37,9 +37,9 @@ package sonia.scm.repository; import com.google.inject.Singleton; +import org.eclipse.jgit.storage.file.FileRepositoryBuilder; + import sonia.scm.Type; -import sonia.scm.io.CommandResult; -import sonia.scm.io.ExtendedCommand; //~--- JDK imports ------------------------------------------------------------ @@ -80,23 +80,6 @@ public class GitRepositoryHandler //~--- methods -------------------------------------------------------------- - /** - * Method description - * - * - * @param repository - * @param directory - * - * @return - */ - @Override - protected ExtendedCommand buildCreateCommand(Repository repository, - File directory) - { - return new ExtendedCommand(config.getGitBinary(), "init", "--bare", - directory.getPath()); - } - /** * Method description * @@ -108,18 +91,11 @@ public class GitRepositoryHandler * @throws RepositoryException */ @Override - protected void postCreate(Repository repository, File directory) - throws IOException, RepositoryException + protected void create(Repository repository, File directory) + throws RepositoryException, IOException { - ExtendedCommand command = new ExtendedCommand(config.getGitBinary(), - "update-server-info"); - - command.setWorkDirectory(directory); - execute(command); - command = new ExtendedCommand(config.getGitBinary(), "config", "--bool", - "--add", "http.receivepack", "true"); - command.setWorkDirectory(directory); - execute(command); + new FileRepositoryBuilder().setGitDir( + directory).readEnvironment().findGitDir().build().create(true); } //~--- get methods ---------------------------------------------------------- @@ -136,30 +112,8 @@ public class GitRepositoryHandler return GitConfig.class; } - //~--- methods -------------------------------------------------------------- + //~--- fields --------------------------------------------------------------- - /** - * Method description - * - * - * @param command - * - * @throws IOException - * @throws RepositoryException - */ - private void execute(ExtendedCommand command) - throws IOException, RepositoryException - { - CommandResult result = command.execute(); - - if (!result.isSuccessfull()) - { - StringBuilder msg = new StringBuilder("command exit with error "); - - msg.append(result.getReturnCode()).append(" and message: '"); - msg.append(result.getOutput()).append("'"); - - throw new RepositoryException(msg.toString()); - } - } + /** Field description */ + private FileRepositoryBuilder builder = new FileRepositoryBuilder(); } diff --git a/plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitRepositoryResolver.java b/plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitRepositoryResolver.java new file mode 100644 index 0000000000..4b85cf1241 --- /dev/null +++ b/plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitRepositoryResolver.java @@ -0,0 +1,192 @@ +/** + * 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 org.eclipse.jgit.errors.RepositoryNotFoundException; +import org.eclipse.jgit.http.server.resolver.RepositoryResolver; +import org.eclipse.jgit.http.server.resolver.ServiceNotAuthorizedException; +import org.eclipse.jgit.http.server.resolver.ServiceNotEnabledException; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.RepositoryCache; +import org.eclipse.jgit.lib.RepositoryCache.FileKey; +import org.eclipse.jgit.util.FS; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import sonia.scm.repository.GitConfig; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; + +/** + * + * @author Sebastian Sdorra + */ +public class GitRepositoryResolver implements RepositoryResolver +{ + + /** the logger for GitRepositoryResolver */ + private static final Logger logger = + LoggerFactory.getLogger(GitRepositoryResolver.class); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param config + */ + public GitRepositoryResolver(GitConfig config) + { + this.config = config; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param name + * + * @return + */ + private static boolean isUnreasonableName(final String name) + { + if (name.length() == 0) + { + return true; // no empty paths + } + + if (name.indexOf('\\') >= 0) + { + return true; // no windows/dos style paths + } + + if (new File(name).isAbsolute()) + { + return true; // no absolute paths + } + + if (name.startsWith("../")) + { + return true; // no "l../etc/passwd" + } + + if (name.contains("/../")) + { + return true; // no "foo/../etc/passwd" + } + + if (name.contains("/./")) + { + return true; // "foo/./foo" is insane to ask + } + + if (name.contains("//")) + { + return true; // double slashes is sloppy, don't use it + } + + return false; // is a reasonable name + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param request + * @param repositoryName + * + * @return + * + * @throws RepositoryNotFoundException + * @throws ServiceNotAuthorizedException + * @throws ServiceNotEnabledException + */ + @Override + public Repository open(HttpServletRequest request, String repositoryName) + throws RepositoryNotFoundException, ServiceNotAuthorizedException, + ServiceNotEnabledException + { + Repository repository = null; + + if (isUnreasonableName(repositoryName)) + { + throw new RepositoryNotFoundException(repositoryName); + } + + try + { + File gitdir = new File(config.getRepositoryDirectory(), repositoryName); + + if (!gitdir.exists()) + { + throw new RepositoryNotFoundException(repositoryName); + } + + repository = RepositoryCache.open(FileKey.lenient(gitdir, FS.DETECTED), + true); + } + catch (RuntimeException e) + { + repository.close(); + + throw new RepositoryNotFoundException(repositoryName, e); + } + catch (IOException e) + { + repository.close(); + + throw new RepositoryNotFoundException(repositoryName, e); + } + + return repository; + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private GitConfig config; +} diff --git a/plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitWebPlugin.java b/plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitWebPlugin.java index 464e63474e..e568f24d31 100644 --- a/plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitWebPlugin.java +++ b/plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitWebPlugin.java @@ -81,7 +81,7 @@ public class GitWebPlugin implements ScmWebPlugin protected void configureServlets() { filter("/git/*").through(BasicAuthenticationFilter.class); - serve("/git/*").with(GitCGIServlet.class); + serve("/git/*").with(ScmGitServlet.class); } }); } diff --git a/plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitCGIServlet.java b/plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServlet.java similarity index 66% rename from plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitCGIServlet.java rename to plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServlet.java index 142dd3e8b4..bee82bf7fe 100644 --- a/plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitCGIServlet.java +++ b/plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServlet.java @@ -29,6 +29,8 @@ * */ + + package sonia.scm.web; //~--- non-JDK imports -------------------------------------------------------- @@ -36,15 +38,13 @@ package sonia.scm.web; import com.google.inject.Inject; import com.google.inject.Singleton; -import sonia.scm.repository.GitConfig; +import org.eclipse.jgit.http.server.GitServlet; + import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.util.IOUtil; -import sonia.scm.web.cgi.AbstractCGIServlet; -import sonia.scm.web.cgi.EnvList; //~--- JDK imports ------------------------------------------------------------ -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -58,15 +58,9 @@ import javax.servlet.http.HttpServletResponse; * @author Sebastian Sdorra */ @Singleton -public class GitCGIServlet extends AbstractCGIServlet +public class ScmGitServlet extends GitServlet { - /** Field description */ - public static final String ENV_HTTP_EXPORT_ALL = "GIT_HTTP_EXPORT_ALL"; - - /** Field description */ - public static final String ENV_PROJECT_ROOT = "GIT_PROJECT_ROOT"; - /** Field description */ public static final String MIMETYPE_HTML = "text/html"; @@ -78,56 +72,24 @@ public class GitCGIServlet extends AbstractCGIServlet public static final String RESOURCE_GITINDEX = "/sonia/scm/git.index.html"; /** Field description */ - private static final long serialVersionUID = 9147517765161830847L; + private static final long serialVersionUID = -7712897339207470674L; + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param handler + */ + @Inject + public ScmGitServlet(GitRepositoryHandler handler) + { + setRepositoryResolver(new GitRepositoryResolver(handler.getConfig())); + } //~--- methods -------------------------------------------------------------- - /** - * Method description - * - * - * @return - * - * @throws ServletException - */ - @Override - protected EnvList createBaseEnvironment() throws ServletException - { - EnvList list = super.createBaseEnvironment(); - - list.set(ENV_HTTP_EXPORT_ALL, ""); - - return list; - } - - /** - * Method description - * - * - * @param baseEnvironment - * - * @return - * - * @throws ServletException - */ - @Override - protected EnvList createRequestEnvironment(EnvList baseEnvironment) - throws ServletException - { - GitConfig config = repositoryHandler.getConfig(); - - if (config == null) - { - throw new ServletException("git is not configured"); - } - - EnvList env = new EnvList(baseEnvironment); - - env.set(ENV_PROJECT_ROOT, config.getRepositoryDirectory().getPath()); - - return env; - } - /** * Method description * @@ -155,35 +117,6 @@ public class GitCGIServlet extends AbstractCGIServlet } } - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @param request - * - * @return - * - * @throws IOException - * @throws ServletException - */ - @Override - protected File getCommand(HttpServletRequest request) - throws ServletException, IOException - { - GitConfig config = repositoryHandler.getConfig(); - - if (config == null) - { - throw new ServletException("git is not configured"); - } - - return new File(config.getGitHttpBackend()); - } - - //~--- methods -------------------------------------------------------------- - /** * Method description * @@ -203,7 +136,7 @@ public class GitCGIServlet extends AbstractCGIServlet try { - input = GitCGIServlet.class.getResourceAsStream(RESOURCE_GITINDEX); + input = ScmGitServlet.class.getResourceAsStream(RESOURCE_GITINDEX); output = response.getOutputStream(); IOUtil.copy(input, output); } @@ -228,10 +161,4 @@ public class GitCGIServlet extends AbstractCGIServlet { return request.getRequestURI().substring(request.getContextPath().length()); } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - @Inject - private GitRepositoryHandler repositoryHandler; } diff --git a/plugins/scm-git-plugin/src/main/resources/sonia/scm/git.config.js b/plugins/scm-git-plugin/src/main/resources/sonia/scm/git.config.js index 9cba6f4b7e..a452710302 100644 --- a/plugins/scm-git-plugin/src/main/resources/sonia/scm/git.config.js +++ b/plugins/scm-git-plugin/src/main/resources/sonia/scm/git.config.js @@ -33,11 +33,6 @@ registerConfigPanel({ xtype : 'configForm', title : 'Git Settings', items : [{ - xtype : 'textfield', - fieldLabel : 'Git Binary', - name : 'gitBinary', - allowBlank : false - },{ xtype: 'textfield', name: 'repositoryDirectory', fieldLabel: 'Repository directory', @@ -47,11 +42,6 @@ registerConfigPanel({ name: 'baseUrl', fieldLabel: 'Base URL', allowBlank : false - },{ - xtype : 'textfield', - fieldLabel : 'Git-Http-Backend', - name : 'gitHttpBackend', - allowBlank : false }], onSubmit: function(values){