diff --git a/plugins/pom.xml b/plugins/pom.xml
index 415e85032e..e91bbca70c 100644
--- a/plugins/pom.xml
+++ b/plugins/pom.xml
@@ -22,6 +22,7 @@
scm-graph-plugin
scm-activedirectory-auth-plugin
scm-pam-plugin
+ scm-bzr-plugin
diff --git a/plugins/scm-bzr-plugin/pom.xml b/plugins/scm-bzr-plugin/pom.xml
new file mode 100644
index 0000000000..81970def67
--- /dev/null
+++ b/plugins/scm-bzr-plugin/pom.xml
@@ -0,0 +1,31 @@
+
+
+
+ 4.0.0
+
+
+ scm-plugins
+ sonia.scm.plugins
+ 1.0-M6-SNAPSHOT
+
+
+ sonia.scm.plugins
+ scm-bzr-plugin
+ 1.0-M6-SNAPSHOT
+ scm-bzr-plugin
+ https://bitbucket.org/sdorra/scm-manager
+ Plugin for the version control system Bazaar
+
+
+
+
+ javax.servlet
+ servlet-api
+ ${servlet.version}
+ provided
+
+
+
+
+
diff --git a/plugins/scm-bzr-plugin/src/main/java/sonia/scm/api/rest/resources/BzrConfigResource.java b/plugins/scm-bzr-plugin/src/main/java/sonia/scm/api/rest/resources/BzrConfigResource.java
new file mode 100644
index 0000000000..f49a845879
--- /dev/null
+++ b/plugins/scm-bzr-plugin/src/main/java/sonia/scm/api/rest/resources/BzrConfigResource.java
@@ -0,0 +1,132 @@
+/**
+ * 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.api.rest.resources;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+import sonia.scm.repository.BzrConfig;
+import sonia.scm.repository.BzrRepositoryHandler;
+import sonia.scm.web.BzrScriptWriter;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.io.IOException;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+@Singleton
+@Path("config/repositories/bzr")
+public class BzrConfigResource
+{
+
+ /**
+ * Constructs ...
+ *
+ *
+ *
+ * @param handler
+ */
+ @Inject
+ public BzrConfigResource(BzrRepositoryHandler handler)
+ {
+ this.handler = handler;
+ }
+
+ //~--- get methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ @GET
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ public BzrConfig getConfig()
+ {
+ BzrConfig config = handler.getConfig();
+
+ if (config == null)
+ {
+ config = new BzrConfig();
+ }
+
+ return config;
+ }
+
+ //~--- set methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param uriInfo
+ * @param config
+ *
+ * @return
+ *
+ * @throws IOException
+ */
+ @POST
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ public Response setConfig(@Context UriInfo uriInfo, BzrConfig config)
+ throws IOException
+ {
+ handler.setConfig(config);
+ handler.storeConfig();
+ new BzrScriptWriter(config).write();
+
+ return Response.created(uriInfo.getRequestUri()).build();
+ }
+
+ //~--- fields ---------------------------------------------------------------
+
+ /** Field description */
+ private BzrRepositoryHandler handler;
+}
diff --git a/plugins/scm-bzr-plugin/src/main/java/sonia/scm/repository/BzrConfig.java b/plugins/scm-bzr-plugin/src/main/java/sonia/scm/repository/BzrConfig.java
new file mode 100644
index 0000000000..deffb169e3
--- /dev/null
+++ b/plugins/scm-bzr-plugin/src/main/java/sonia/scm/repository/BzrConfig.java
@@ -0,0 +1,134 @@
+/**
+ * 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;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+@XmlRootElement(name = "config")
+public class BzrConfig extends SimpleRepositoryConfig
+{
+
+ /**
+ * Constructs ...
+ *
+ */
+ public BzrConfig() {}
+
+ //~--- get methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ public String getBzrBinary()
+ {
+ return bzrBinary;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ public String getPythonBinary()
+ {
+ return pythonBinary;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ public String getPythonPath()
+ {
+ return pythonPath;
+ }
+
+ //~--- set methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param bzrBinary
+ */
+ public void setBzrBinary(String bzrBinary)
+ {
+ this.bzrBinary = bzrBinary;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param pythonBinary
+ */
+ public void setPythonBinary(String pythonBinary)
+ {
+ this.pythonBinary = pythonBinary;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param pythonPath
+ */
+ public void setPythonPath(String pythonPath)
+ {
+ this.pythonPath = pythonPath;
+ }
+
+ //~--- fields ---------------------------------------------------------------
+
+ /** Field description */
+ private String bzrBinary;
+
+ /** Field description */
+ private String pythonBinary;
+
+ /** Field description */
+ private String pythonPath = "";
+}
diff --git a/plugins/scm-bzr-plugin/src/main/java/sonia/scm/repository/BzrRepositoryHandler.java b/plugins/scm-bzr-plugin/src/main/java/sonia/scm/repository/BzrRepositoryHandler.java
new file mode 100644
index 0000000000..4a454d0ec0
--- /dev/null
+++ b/plugins/scm-bzr-plugin/src/main/java/sonia/scm/repository/BzrRepositoryHandler.java
@@ -0,0 +1,129 @@
+/**
+ * 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.Inject;
+import com.google.inject.Singleton;
+
+import sonia.scm.Type;
+import sonia.scm.io.ExtendedCommand;
+import sonia.scm.plugin.ext.Extension;
+import sonia.scm.store.StoreFactory;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.io.File;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+@Singleton
+@Extension
+public class BzrRepositoryHandler
+ extends AbstractSimpleRepositoryHandler
+{
+
+ /** Field description */
+ public static final String TYPE_DISPLAYNAME = "Bazaar";
+
+ /** Field description */
+ public static final String TYPE_NAME = "bzr";
+
+ /** Field description */
+ public static final Type TYPE = new Type(TYPE_NAME, TYPE_DISPLAYNAME);
+
+ //~--- constructors ---------------------------------------------------------
+
+ /**
+ * Constructs ...
+ *
+ *
+ * @param storeFactory
+ */
+ @Inject
+ public BzrRepositoryHandler(StoreFactory storeFactory)
+ {
+ super(storeFactory);
+ }
+
+ //~--- get methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ @Override
+ public Type getType()
+ {
+ return TYPE;
+ }
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param repository
+ * @param directory
+ *
+ * @return
+ */
+ @Override
+ protected ExtendedCommand buildCreateCommand(Repository repository,
+ File directory)
+ {
+ return new ExtendedCommand(config.getBzrBinary(), "init-repo",
+ "--no-trees", directory.getPath());
+ }
+
+ //~--- get methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ @Override
+ protected Class getConfigClass()
+ {
+ return BzrConfig.class;
+ }
+}
diff --git a/plugins/scm-bzr-plugin/src/main/java/sonia/scm/web/BzrCGIServlet.java b/plugins/scm-bzr-plugin/src/main/java/sonia/scm/web/BzrCGIServlet.java
new file mode 100644
index 0000000000..358b7bbcd2
--- /dev/null
+++ b/plugins/scm-bzr-plugin/src/main/java/sonia/scm/web/BzrCGIServlet.java
@@ -0,0 +1,253 @@
+/**
+ * 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 sonia.scm.repository.BzrConfig;
+import sonia.scm.repository.BzrRepositoryHandler;
+import sonia.scm.repository.Repository;
+import sonia.scm.repository.RepositoryManager;
+import sonia.scm.util.AssertUtil;
+import sonia.scm.web.cgi.AbstractCGIServlet;
+import sonia.scm.web.cgi.EnvList;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.io.File;
+import java.io.IOException;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+@Singleton
+public class BzrCGIServlet extends AbstractCGIServlet
+{
+
+ /** Field description */
+ public static final String ENV_PYTHON_PATH = "SCM_PYTHON_PATH";
+
+ /** Field description */
+ public static final String ENV_REPOSITORY_NAME = "REPO_NAME";
+
+ /** Field description */
+ public static final String ENV_REPOSITORY_PATH = "SCM_REPOSITORY_PATH";
+
+ /** Field description */
+ private static final long serialVersionUID = 7674689744455227632L;
+
+ /** Field description */
+ public static final Pattern PATTERN_REPOSITORYNAME =
+ Pattern.compile("/[^/]+/([^/]+)(?:/.*)?");
+
+ //~--- constructors ---------------------------------------------------------
+
+ /**
+ * Constructs ...
+ *
+ *
+ * @param repositoryManager
+ * @param handler
+ */
+ @Inject
+ public BzrCGIServlet(RepositoryManager repositoryManager,
+ BzrRepositoryHandler handler)
+ {
+ this.repositoryManager = repositoryManager;
+ this.handler = handler;
+ }
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @throws ServletException
+ */
+ @Override
+ public void init() throws ServletException
+ {
+ command = BzrUtil.getCGI();
+ super.init();
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param request
+ * @param baseEnvironment
+ *
+ * @return
+ *
+ * @throws ServletException
+ */
+ @Override
+ protected EnvList createRequestEnvironment(HttpServletRequest request,
+ EnvList baseEnvironment)
+ throws ServletException
+ {
+ EnvList list = new EnvList(baseEnvironment);
+ Repository repository = getRepository(request);
+
+ if (repository == null)
+ {
+ throw new ServletException("repository not found");
+ }
+
+ String name = repository.getName();
+ File directory = handler.getDirectory(repository);
+
+ list.set(ENV_REPOSITORY_PATH, directory.getAbsolutePath());
+ list.set(ENV_REPOSITORY_NAME, name);
+
+ String pythonPath = "";
+ BzrConfig config = handler.getConfig();
+
+ if (config != null)
+ {
+ pythonPath = config.getPythonPath();
+
+ if (pythonPath == null)
+ {
+ pythonPath = "";
+ }
+ }
+
+ list.set(ENV_PYTHON_PATH, pythonPath);
+
+ return list;
+ }
+
+ //~--- get methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ *
+ * @return
+ *
+ */
+ @Override
+ protected String getCmdPrefix()
+ {
+ BzrConfig config = handler.getConfig();
+
+ AssertUtil.assertIsNotNull(config);
+
+ return config.getPythonBinary();
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param request
+ *
+ * @return
+ *
+ * @throws IOException
+ * @throws ServletException
+ */
+ @Override
+ protected File getCommand(HttpServletRequest request)
+ throws ServletException, IOException
+ {
+ return command;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param request
+ *
+ * @return
+ */
+ private Repository getRepository(HttpServletRequest request)
+ {
+ Repository repository = null;
+ String uri = request.getRequestURI();
+
+ uri = uri.substring(request.getContextPath().length());
+
+ Matcher m = PATTERN_REPOSITORYNAME.matcher(uri);
+
+ if (m.matches())
+ {
+ String repositoryname = m.group(1);
+
+ repository = getRepository(repositoryname);
+ }
+
+ return repository;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param repositoryname
+ *
+ * @return
+ */
+ private Repository getRepository(String repositoryname)
+ {
+ return repositoryManager.get(BzrRepositoryHandler.TYPE_NAME,
+ repositoryname);
+ }
+
+ //~--- fields ---------------------------------------------------------------
+
+ /** Field description */
+ private File command;
+
+ /** Field description */
+ private BzrRepositoryHandler handler;
+
+ /** Field description */
+ private RepositoryManager repositoryManager;
+}
diff --git a/plugins/scm-bzr-plugin/src/main/java/sonia/scm/web/BzrPermissionFilter.java b/plugins/scm-bzr-plugin/src/main/java/sonia/scm/web/BzrPermissionFilter.java
new file mode 100644
index 0000000000..65737a88be
--- /dev/null
+++ b/plugins/scm-bzr-plugin/src/main/java/sonia/scm/web/BzrPermissionFilter.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.web;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+import sonia.scm.repository.BzrRepositoryHandler;
+import sonia.scm.repository.RepositoryManager;
+import sonia.scm.web.filter.RegexPermissionFilter;
+import sonia.scm.web.security.WebSecurityContext;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+@Singleton
+public class BzrPermissionFilter extends RegexPermissionFilter
+{
+
+ /**
+ * Constructs ...
+ *
+ *
+ * @param securityContextProvider
+ * @param repositoryManager
+ */
+ @Inject
+ public BzrPermissionFilter(
+ Provider securityContextProvider,
+ RepositoryManager repositoryManager)
+ {
+ super(securityContextProvider, repositoryManager);
+ }
+
+ //~--- get methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ @Override
+ protected String getType()
+ {
+ return BzrRepositoryHandler.TYPE_NAME;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param request
+ *
+ * @return
+ */
+ @Override
+ protected boolean isWriteRequest(HttpServletRequest request)
+ {
+ return !request.getMethod().equalsIgnoreCase("GET");
+ }
+}
diff --git a/plugins/scm-bzr-plugin/src/main/java/sonia/scm/web/BzrScriptWriter.java b/plugins/scm-bzr-plugin/src/main/java/sonia/scm/web/BzrScriptWriter.java
new file mode 100644
index 0000000000..022dbf89ab
--- /dev/null
+++ b/plugins/scm-bzr-plugin/src/main/java/sonia/scm/web/BzrScriptWriter.java
@@ -0,0 +1,125 @@
+/**
+ * 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 sonia.scm.io.RegexResourceProcessor;
+import sonia.scm.io.ResourceProcessor;
+import sonia.scm.repository.BzrConfig;
+import sonia.scm.util.IOUtil;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public class BzrScriptWriter
+{
+
+ /** Field description */
+ public static final String CGI_TEMPLATE = "/sonia/scm/bzrweb.py";
+
+ //~--- constructors ---------------------------------------------------------
+
+ /**
+ * Constructs ...
+ *
+ *
+ * @param config
+ */
+ public BzrScriptWriter(BzrConfig config)
+ {
+ this.config = config;
+ }
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ *
+ * @throws IOException
+ */
+ public void write() throws IOException
+ {
+ File cgiFile = BzrUtil.getCGI();
+
+ writeCGIFile(cgiFile);
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param cgiFile
+ *
+ * @throws IOException
+ */
+ private void writeCGIFile(File cgiFile) throws IOException
+ {
+ InputStream input = null;
+ OutputStream output = null;
+
+ try
+ {
+ input = BzrScriptWriter.class.getResourceAsStream(CGI_TEMPLATE);
+ output = new FileOutputStream(cgiFile);
+
+ ResourceProcessor rp = new RegexResourceProcessor();
+
+ rp.addVariable("python", config.getPythonBinary());
+ rp.process(input, output);
+ cgiFile.setExecutable(true);
+ }
+ finally
+ {
+ IOUtil.close(input);
+ IOUtil.close(output);
+ }
+ }
+
+ //~--- fields ---------------------------------------------------------------
+
+ /** Field description */
+ private BzrConfig config;
+}
diff --git a/plugins/scm-bzr-plugin/src/main/java/sonia/scm/web/BzrServletModule.java b/plugins/scm-bzr-plugin/src/main/java/sonia/scm/web/BzrServletModule.java
new file mode 100644
index 0000000000..086a81cafc
--- /dev/null
+++ b/plugins/scm-bzr-plugin/src/main/java/sonia/scm/web/BzrServletModule.java
@@ -0,0 +1,67 @@
+/**
+ * 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.servlet.ServletModule;
+
+import sonia.scm.plugin.ext.Extension;
+import sonia.scm.web.filter.BasicAuthenticationFilter;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+@Extension
+public class BzrServletModule extends ServletModule
+{
+
+ /** Field description */
+ public static final String MAPPING_BZR = "/bzr/*";
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ */
+ @Override
+ protected void configureServlets()
+ {
+ filter(MAPPING_BZR).through(BasicAuthenticationFilter.class);
+ filter(MAPPING_BZR).through(BzrPermissionFilter.class);
+ serve(MAPPING_BZR).with(BzrCGIServlet.class);
+ }
+}
diff --git a/plugins/scm-bzr-plugin/src/main/java/sonia/scm/web/BzrUtil.java b/plugins/scm-bzr-plugin/src/main/java/sonia/scm/web/BzrUtil.java
new file mode 100644
index 0000000000..7e956c3cba
--- /dev/null
+++ b/plugins/scm-bzr-plugin/src/main/java/sonia/scm/web/BzrUtil.java
@@ -0,0 +1,78 @@
+/**
+ * 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 sonia.scm.SCMContext;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.io.File;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public class BzrUtil
+{
+
+ /** Field description */
+ public static final String CGI_DIRECTORY = "cgi-bin";
+
+ /** Field description */
+ public static final String CGI_NAME = "bzrweb.py";
+
+ //~--- get methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ public static File getCGI()
+ {
+ File cgiDirectory = new File(SCMContext.getContext().getBaseDirectory(),
+ CGI_DIRECTORY);
+
+ if (!cgiDirectory.exists() &&!cgiDirectory.mkdirs())
+ {
+ throw new RuntimeException(
+ "could not create directory".concat(cgiDirectory.getPath()));
+ }
+
+ return new File(cgiDirectory, CGI_NAME);
+ }
+}
diff --git a/plugins/scm-bzr-plugin/src/main/resources/META-INF/scm/plugin.xml b/plugins/scm-bzr-plugin/src/main/resources/META-INF/scm/plugin.xml
new file mode 100644
index 0000000000..451c4a6467
--- /dev/null
+++ b/plugins/scm-bzr-plugin/src/main/resources/META-INF/scm/plugin.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+ ${project.groupId}
+ ${project.artifactId}
+ ${project.version}
+ ${project.name}
+ ${project.description}
+ Sebastian Sdorra
+ ${project.url}
+
+
+
+
+
+
+
diff --git a/plugins/scm-bzr-plugin/src/main/resources/sonia/scm/bzr.config.js b/plugins/scm-bzr-plugin/src/main/resources/sonia/scm/bzr.config.js
new file mode 100644
index 0000000000..6212aa3cde
--- /dev/null
+++ b/plugins/scm-bzr-plugin/src/main/resources/sonia/scm/bzr.config.js
@@ -0,0 +1,96 @@
+/* *
+ * 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
+ *
+ */
+
+
+
+registerConfigPanel({
+ xtype : 'configForm',
+ title : 'Bazaar Settings',
+ items : [{
+ xtype : 'textfield',
+ fieldLabel : 'Bzr Binary',
+ name : 'bzrBinary',
+ allowBlank : false
+ },{
+ xtype : 'textfield',
+ fieldLabel : 'Python Binary',
+ name : 'pythonBinary',
+ allowBlank : false
+ },{
+ xtype : 'textfield',
+ fieldLabel : 'Python Path',
+ name : 'pythonPath'
+ },{
+ xtype: 'textfield',
+ name: 'repositoryDirectory',
+ fieldLabel: 'Repository directory',
+ allowBlank : false
+ }],
+
+ onSubmit: function(values){
+ this.el.mask('Submit ...');
+ Ext.Ajax.request({
+ url: restUrl + 'config/repositories/bzr.json',
+ method: 'POST',
+ jsonData: values,
+ scope: this,
+ disableCaching: true,
+ success: function(response){
+ this.el.unmask();
+ },
+ failure: function(){
+ this.el.unmask();
+ }
+ });
+ },
+
+ onLoad: function(el){
+ var tid = setTimeout( function(){ el.mask('Loading ...'); }, 100);
+ Ext.Ajax.request({
+ url: restUrl + 'config/repositories/bzr.json',
+ method: 'GET',
+ scope: this,
+ disableCaching: true,
+ success: function(response){
+ var obj = Ext.decode(response.responseText);
+ this.load(obj);
+ clearTimeout(tid);
+ el.unmask();
+ },
+ failure: function(){
+ el.unmask();
+ clearTimeout(tid);
+ alert('failure');
+ }
+ });
+ }
+
+});
diff --git a/plugins/scm-bzr-plugin/src/main/resources/sonia/scm/bzrweb.py b/plugins/scm-bzr-plugin/src/main/resources/sonia/scm/bzrweb.py
new file mode 100644
index 0000000000..ac07f87421
--- /dev/null
+++ b/plugins/scm-bzr-plugin/src/main/resources/sonia/scm/bzrweb.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env ${python}
+
+import os, sys
+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])
+
+repositoryPath = os.environ['SCM_REPOSITORY_PATH']
+repositoryName = os.environ['REPO_NAME']
+
+def run_with_cgi(application):
+
+ environ = dict(os.environ.items())
+ environ['wsgi.input'] = sys.stdin
+ environ['wsgi.errors'] = sys.stderr
+ environ['wsgi.version'] = (1, 0)
+ environ['wsgi.multithread'] = False
+ environ['wsgi.multiprocess'] = True
+ environ['wsgi.run_once'] = True
+
+ if environ.get('HTTPS', 'off') in ('on', '1'):
+ environ['wsgi.url_scheme'] = 'https'
+ else:
+ environ['wsgi.url_scheme'] = 'http'
+
+ headers_set = []
+ headers_sent = []
+
+ def write(data):
+ if not headers_set:
+ raise AssertionError("write() before start_response()")
+
+ elif not headers_sent:
+ # Before the first output, send the stored headers
+ status, response_headers = headers_sent[:] = headers_set
+ sys.stdout.write('Status: %s\r\n' % status)
+ for header in response_headers:
+ sys.stdout.write('%s: %s\r\n' % header)
+ sys.stdout.write('\r\n')
+
+ sys.stdout.write(data)
+ sys.stdout.flush()
+
+ def start_response(status, response_headers, exc_info=None):
+ if exc_info:
+ try:
+ if headers_sent:
+ # Re-raise original exception if headers sent
+ raise exc_info[0], exc_info[1], exc_info[2]
+ finally:
+ exc_info = None # avoid dangling circular ref
+ elif headers_set:
+ raise AssertionError("Headers already set!")
+
+ headers_set[:] = [status, response_headers]
+ return write
+
+ result = application(environ, start_response)
+ try:
+ for data in result:
+ if data: # don't send headers until body appears
+ write(data)
+ if not headers_sent:
+ write('') # send headers now if body was empty
+ finally:
+ if hasattr(result, 'close'):
+ result.close()
+
+from bzrlib.transport.http import wsgi
+
+def application(environ, start_response):
+ app = wsgi.make_app(
+ root=repositoryPath,
+ prefix="/"+repositoryName,
+ path_var='PATH_INFO',
+ readonly=False,
+ enable_logging=True)
+ return app(environ, start_response)
+
+run_with_cgi(application)
\ No newline at end of file
diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml
index d8df5e192a..d1038a6558 100644
--- a/scm-webapp/pom.xml
+++ b/scm-webapp/pom.xml
@@ -266,6 +266,12 @@
1.0-M6-SNAPSHOT
+
+ sonia.scm.plugins
+ scm-bzr-plugin
+ 1.0-M6-SNAPSHOT
+
+