diff --git a/plugins/pom.xml b/plugins/pom.xml
index ba78057d2d..fb4f93a261 100644
--- a/plugins/pom.xml
+++ b/plugins/pom.xml
@@ -17,6 +17,7 @@
scm-hg-plugin
+ scm-svn-plugin
diff --git a/plugins/scm-svn-plugin/pom.xml b/plugins/scm-svn-plugin/pom.xml
new file mode 100644
index 0000000000..650325decd
--- /dev/null
+++ b/plugins/scm-svn-plugin/pom.xml
@@ -0,0 +1,18 @@
+
+
+
+ 4.0.0
+
+
+ scm-plugins
+ sonia.scm.plugins
+ 1.0-SNAPSHOT
+
+
+ sonia.scm.plugins
+ scm-svn-plugin
+ 1.0-SNAPSHOT
+ scm-svn-plugin
+
+
diff --git a/plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnConfig.java b/plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnConfig.java
new file mode 100644
index 0000000000..577b5d1c86
--- /dev/null
+++ b/plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnConfig.java
@@ -0,0 +1,100 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+
+
+package sonia.scm.repository;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+@XmlRootElement(name = "config")
+public class SvnConfig extends BasicRepositoryConfig
+{
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ public String getRepositoryDirectory()
+ {
+ return repositoryDirectory;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ public String getSvnAccessFile()
+ {
+ return svnAccessFile;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ public String getSvnAdminBinary()
+ {
+ return svnAdminBinary;
+ }
+
+ //~--- set methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param repositoryDirectory
+ */
+ public void setRepositoryDirectory(String repositoryDirectory)
+ {
+ this.repositoryDirectory = repositoryDirectory;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param svnAccessFile
+ */
+ public void setSvnAccessFile(String svnAccessFile)
+ {
+ this.svnAccessFile = svnAccessFile;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param svnAdminBinary
+ */
+ public void setSvnAdminBinary(String svnAdminBinary)
+ {
+ this.svnAdminBinary = svnAdminBinary;
+ }
+
+ //~--- fields ---------------------------------------------------------------
+
+ /** Field description */
+ private String repositoryDirectory;
+
+ /** Field description */
+ private String svnAccessFile;
+
+ /** Field description */
+ private String svnAdminBinary;
+}
diff --git a/plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnRepositoryHandler.java b/plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnRepositoryHandler.java
new file mode 100644
index 0000000000..4a3a9a2c30
--- /dev/null
+++ b/plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnRepositoryHandler.java
@@ -0,0 +1,332 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+
+
+package sonia.scm.repository;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import sonia.scm.ConfigurationException;
+import sonia.scm.SCMContextProvider;
+import sonia.scm.io.CommandResult;
+import sonia.scm.io.ExtendedCommand;
+import sonia.scm.util.Util;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.xml.bind.JAXB;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public class SvnRepositoryHandler extends AbstractRepositoryHandler
+{
+
+ /** Field description */
+ public static final String TYPE_DISPLAYNAME = "Subversion";
+
+ /** Field description */
+ public static final String TYPE_NAME = "svn";
+
+ /** Field description */
+ public static final RepositoryType TYPE = new RepositoryType(TYPE_NAME,
+ TYPE_DISPLAYNAME);
+
+ /** Field description */
+ private static final Logger logger =
+ Logger.getLogger(SvnRepositoryHandler.class.getName());
+
+ /** Field description */
+ public static final String CONFIG_DIRECTORY =
+ "config".concat(File.separator).concat("svn");
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param repository
+ *
+ * @throws IOException
+ * @throws RepositoryException
+ */
+ @Override
+ public void create(Repository repository)
+ throws RepositoryException, IOException
+ {
+ initNewRepository(repository);
+
+ File directory = getDirectory(repository);
+
+ if (directory.exists())
+ {
+ throw new RepositoryAllreadyExistExeption();
+ }
+
+ ExtendedCommand cmd = new ExtendedCommand(config.getSvnAdminBinary(),
+ "create", directory.getPath());
+ CommandResult result = cmd.execute();
+
+ if (!result.isSuccessfull())
+ {
+ StringBuilder msg = new StringBuilder("svnadmin exit with error ");
+
+ msg.append(result.getReturnCode()).append(" and message: '");
+ msg.append(result.getOutput()).append("'");
+
+ throw new RepositoryException(msg.toString());
+ }
+
+ repository.setType(TYPE_NAME);
+ JAXB.marshal(repository, getRepositoryFile(repository));
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param repository
+ *
+ * @throws IOException
+ * @throws RepositoryException
+ */
+ @Override
+ public void delete(Repository repository)
+ throws RepositoryException, IOException
+ {
+ File directory = getDirectory(repository);
+ File repositoryFile = getRepositoryFile(repository);
+
+ if (directory.exists() && repositoryFile.exists())
+ {
+ Util.delete(directory);
+ Util.delete(repositoryFile);
+ }
+ else
+ {
+ throw new RepositoryException("repository does not exists");
+ }
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param context
+ */
+ @Override
+ public void init(SCMContextProvider context)
+ {
+ super.init(context);
+
+ File baseDirectory = context.getBaseDirectory();
+
+ configDirectory = new File(baseDirectory, CONFIG_DIRECTORY);
+
+ if (!configDirectory.exists() &&!configDirectory.mkdirs())
+ {
+ throw new ConfigurationException("could not create config directory");
+ }
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param repository
+ *
+ * @throws IOException
+ * @throws RepositoryException
+ */
+ @Override
+ public void modify(Repository repository)
+ throws RepositoryException, IOException
+ {
+ Repository old = get(repository.getId());
+
+ if (old.getName().equals(repository.getName()))
+ {
+ JAXB.marshal(repository, getRepositoryFile(repository));
+ }
+ else
+ {
+ throw new RepositoryException(
+ "the name of a repository could not changed");
+ }
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param repository
+ *
+ * @throws IOException
+ * @throws RepositoryException
+ */
+ @Override
+ public void refresh(Repository repository)
+ throws RepositoryException, IOException
+ {
+ Repository fresh = get(repository.getId());
+
+ fresh.copyProperties(repository);
+ }
+
+ //~--- get methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param id
+ *
+ * @return
+ */
+ @Override
+ public Repository get(String id)
+ {
+ Repository repository = null;
+ File repositoryFile = getRepositoryFile(id);
+
+ if (repositoryFile.exists())
+ {
+ repository = JAXB.unmarshal(repositoryFile, Repository.class);
+ }
+
+ return repository;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ @Override
+ public Collection getAll()
+ {
+ List repositories = new ArrayList();
+ File[] repositoryFiles = configDirectory.listFiles(new FilenameFilter()
+ {
+ @Override
+ public boolean accept(File dir, String name)
+ {
+ return name.endsWith(".xml");
+ }
+ });
+
+ for (File repositoryFile : repositoryFiles)
+ {
+ try
+ {
+ Repository repository = JAXB.unmarshal(repositoryFile,
+ Repository.class);
+
+ repositories.add(repository);
+ }
+ catch (Exception ex)
+ {
+ logger.log(Level.SEVERE, null, ex);
+ }
+ }
+
+ return repositories;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ @Override
+ public RepositoryType getType()
+ {
+ return TYPE;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ @Override
+ protected Class getConfigClass()
+ {
+ return SvnConfig.class;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param repository
+ *
+ * @return
+ */
+ protected File getDirectory(Repository repository)
+ {
+ File directory = null;
+
+ if (isConfigured())
+ {
+ directory = new File(config.getRepositoryDirectory(),
+ repository.getName());
+ }
+ else
+ {
+ throw new ConfigurationException("RepositoryHandler is not configured");
+ }
+
+ return directory;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ *
+ * @param id
+ *
+ * @return
+ */
+ private File getRepositoryFile(String id)
+ {
+ return new File(configDirectory, id.concat(".xml"));
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param repository
+ *
+ * @return
+ */
+ private File getRepositoryFile(Repository repository)
+ {
+ return getRepositoryFile(repository.getId());
+ }
+
+ //~--- fields ---------------------------------------------------------------
+
+ /** Field description */
+ private File configDirectory;
+}
diff --git a/plugins/scm-svn-plugin/src/main/resources/META-INF/services/sonia.scm.repository.RepositoryHandler b/plugins/scm-svn-plugin/src/main/resources/META-INF/services/sonia.scm.repository.RepositoryHandler
new file mode 100644
index 0000000000..ab9c76f40a
--- /dev/null
+++ b/plugins/scm-svn-plugin/src/main/resources/META-INF/services/sonia.scm.repository.RepositoryHandler
@@ -0,0 +1 @@
+sonia.scm.repository.SvnRepositoryHandler
\ No newline at end of file
diff --git a/scm-core/src/main/java/sonia/scm/repository/Repository.java b/scm-core/src/main/java/sonia/scm/repository/Repository.java
index 636910b92e..f50c697a78 100644
--- a/scm-core/src/main/java/sonia/scm/repository/Repository.java
+++ b/scm-core/src/main/java/sonia/scm/repository/Repository.java
@@ -96,6 +96,24 @@ public class Repository implements Serializable
}
}
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param repository
+ */
+ public void copyProperties(Repository repository)
+ {
+ repository.setName(name);
+ repository.setContact(contact);
+ repository.setCreationDate(creationDate);
+ repository.setDescription(description);
+ repository.setPermissions(permissions);
+ repository.setUrl(url);
+ }
+
//~--- get methods ----------------------------------------------------------
/**
diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml
index a8e5c37171..49181b7e0f 100644
--- a/scm-webapp/pom.xml
+++ b/scm-webapp/pom.xml
@@ -43,6 +43,12 @@
1.0-SNAPSHOT
+
+ sonia.scm.plugins
+ scm-svn-plugin
+ 1.0-SNAPSHOT
+
+
com.sun.jersey
jersey-json