From fa1d433a368d6754d0519c82bdbdcab993033211 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 1 Jul 2011 18:43:26 +0200 Subject: [PATCH] move core plugins back to main repository, because of a broken release management --- scm-plugins/pom.xml | 4 + scm-plugins/scm-git-plugin/pom.xml | 86 ++++ .../api/rest/resources/GitConfigResource.java | 124 +++++ .../scm/repository/GitChangesetViewer.java | 305 ++++++++++++ .../java/sonia/scm/repository/GitConfig.java | 45 ++ .../scm/repository/GitRepositoryBrowser.java | 338 +++++++++++++ .../scm/repository/GitRepositoryHandler.java | 208 ++++++++ .../java/sonia/scm/repository/GitUtil.java | 167 +++++++ .../sonia/scm/web/GitPermissionFilter.java | 121 +++++ .../sonia/scm/web/GitRepositoryResolver.java | 210 ++++++++ .../sonia/scm/web/GitRepositoryViewer.java | 205 ++++++++ .../java/sonia/scm/web/GitServletModule.java | 67 +++ .../java/sonia/scm/web/ScmGitServlet.java | 176 +++++++ .../main/resources/META-INF/scm/plugin.xml | 63 +++ .../main/resources/sonia/scm/git.config.js | 97 ++++ .../main/resources/sonia/scm/git.index.html | 114 +++++ .../repository/GitRepositoryHandlerTest.java | 104 ++++ scm-plugins/scm-hg-plugin/pom.xml | 56 +++ .../api/rest/resources/HgConfigResource.java | 351 ++++++++++++++ .../scm/installer/AbstractHgInstaller.java | 102 ++++ .../java/sonia/scm/installer/HgInstaller.java | 113 +++++ .../scm/installer/HgInstallerFactory.java | 68 +++ .../java/sonia/scm/installer/HgPackage.java | 262 ++++++++++ .../scm/installer/HgPackageInstaller.java | 269 +++++++++++ .../sonia/scm/installer/HgPackageReader.java | 254 ++++++++++ .../java/sonia/scm/installer/HgPackages.java | 98 ++++ .../sonia/scm/installer/UnixHgInstaller.java | 152 ++++++ .../scm/installer/WindowsHgInstaller.java | 428 +++++++++++++++++ .../scm/repository/HgChangesetParser.java | 238 ++++++++++ .../scm/repository/HgChangesetViewer.java | 237 +++++++++ .../java/sonia/scm/repository/HgConfig.java | 176 +++++++ .../scm/repository/HgRepositoryBrowser.java | 238 ++++++++++ .../scm/repository/HgRepositoryHandler.java | 290 +++++++++++ .../main/java/sonia/scm/web/HgCGIServlet.java | 263 ++++++++++ .../sonia/scm/web/HgPermissionFilter.java | 101 ++++ .../java/sonia/scm/web/HgServletModule.java | 67 +++ .../src/main/java/sonia/scm/web/HgUtil.java | 78 +++ .../java/sonia/scm/web/HgWebConfigWriter.java | 125 +++++ .../main/resources/META-INF/scm/plugin.xml | 64 +++ .../resources/sonia/scm/hg.config-wizard.js | 449 ++++++++++++++++++ .../src/main/resources/sonia/scm/hg.config.js | 211 ++++++++ .../src/main/resources/sonia/scm/hgbrowse.py | 82 ++++ .../src/main/resources/sonia/scm/hgweb.py | 16 + .../repository/HgRepositoryHandlerTest.java | 104 ++++ scm-plugins/scm-svn-plugin/pom.xml | 70 +++ .../api/rest/resources/SvnConfigResource.java | 125 +++++ .../sonia/scm/repository/Compatibility.java | 105 ++++ .../scm/repository/SvnChangesetViewer.java | 207 ++++++++ .../java/sonia/scm/repository/SvnConfig.java | 81 ++++ .../scm/repository/SvnRepositoryBrowser.java | 290 +++++++++++ .../scm/repository/SvnRepositoryHandler.java | 227 +++++++++ .../main/java/sonia/scm/web/SvnDAVConfig.java | 240 ++++++++++ .../java/sonia/scm/web/SvnDAVServlet.java | 89 ++++ .../sonia/scm/web/SvnPermissionFilter.java | 114 +++++ .../java/sonia/scm/web/SvnServletModule.java | 80 ++++ .../main/resources/META-INF/scm/plugin.xml | 63 +++ .../main/resources/sonia/scm/svn.config.js | 124 +++++ .../repository/SvnRepositoryHandlerTest.java | 99 ++++ 58 files changed, 9240 insertions(+) create mode 100644 scm-plugins/scm-git-plugin/pom.xml create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/rest/resources/GitConfigResource.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitChangesetViewer.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitConfig.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryBrowser.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryHandler.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitRepositoryResolver.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitRepositoryViewer.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServlet.java create mode 100644 scm-plugins/scm-git-plugin/src/main/resources/META-INF/scm/plugin.xml create mode 100644 scm-plugins/scm-git-plugin/src/main/resources/sonia/scm/git.config.js create mode 100644 scm-plugins/scm-git-plugin/src/main/resources/sonia/scm/git.index.html create mode 100644 scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryHandlerTest.java create mode 100644 scm-plugins/scm-hg-plugin/pom.xml create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/rest/resources/HgConfigResource.java create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/AbstractHgInstaller.java create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgInstaller.java create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgInstallerFactory.java create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgPackage.java create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgPackageInstaller.java create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgPackageReader.java create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgPackages.java create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/UnixHgInstaller.java create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/WindowsHgInstaller.java create 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/HgChangesetViewer.java create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgConfig.java create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryBrowser.java create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgUtil.java create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgWebConfigWriter.java create mode 100644 scm-plugins/scm-hg-plugin/src/main/resources/META-INF/scm/plugin.xml create mode 100644 scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hg.config-wizard.js create mode 100644 scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hg.config.js create mode 100644 scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hgbrowse.py create mode 100644 scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hgweb.py create mode 100644 scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/HgRepositoryHandlerTest.java create mode 100644 scm-plugins/scm-svn-plugin/pom.xml create mode 100644 scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/api/rest/resources/SvnConfigResource.java create mode 100644 scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/Compatibility.java create mode 100644 scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnChangesetViewer.java create mode 100644 scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnConfig.java create mode 100644 scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnRepositoryBrowser.java create mode 100644 scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnRepositoryHandler.java create mode 100644 scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVConfig.java create mode 100644 scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java create mode 100644 scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java create mode 100644 scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java create mode 100644 scm-plugins/scm-svn-plugin/src/main/resources/META-INF/scm/plugin.xml create mode 100644 scm-plugins/scm-svn-plugin/src/main/resources/sonia/scm/svn.config.js create mode 100644 scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/SvnRepositoryHandlerTest.java diff --git a/scm-plugins/pom.xml b/scm-plugins/pom.xml index 6b10d80504..b178a3158d 100644 --- a/scm-plugins/pom.xml +++ b/scm-plugins/pom.xml @@ -18,6 +18,10 @@ scm-activedirectory-auth-plugin scm-auth-ldap-plugin + + scm-hg-plugin + scm-git-plugin + scm-svn-plugin diff --git a/scm-plugins/scm-git-plugin/pom.xml b/scm-plugins/scm-git-plugin/pom.xml new file mode 100644 index 0000000000..9cc833a901 --- /dev/null +++ b/scm-plugins/scm-git-plugin/pom.xml @@ -0,0 +1,86 @@ + + + + 4.0.0 + + + scm-plugins + sonia.scm.plugins + 1.5-SNAPSHOT + + + sonia.scm.plugins + scm-git-plugin + 1.5-SNAPSHOT + scm-git-plugin + https://bitbucket.org/sdorra/scm-manager + Plugin for the version control system Git + + + + + javax.servlet + servlet-api + ${servlet.version} + provided + + + + org.eclipse.jgit + org.eclipse.jgit + ${jgit.version} + + + com.jcraft + jsch + + + + + + + org.eclipse.jgit + org.eclipse.jgit.http.server + ${jgit.version} + + + + commons-lang + commons-lang + 2.6 + + + + + + sonia.scm + scm-test + 1.5-SNAPSHOT + test + + + + + + 1.0.0.201106090707-r + + + + + + + + jgit-repository + http://download.eclipse.org/jgit/maven + + + + maven.scm-manager.org + scm-manager release repository + http://maven.scm-manager.org/nexus/content/groups/public + + + + + diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/rest/resources/GitConfigResource.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/rest/resources/GitConfigResource.java new file mode 100644 index 0000000000..4ecc2f07e7 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/rest/resources/GitConfigResource.java @@ -0,0 +1,124 @@ +/** + * 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.GitConfig; +import sonia.scm.repository.GitRepositoryHandler; + +//~--- JDK imports ------------------------------------------------------------ + +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/git") +@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) +public class GitConfigResource +{ + + /** + * Constructs ... + * + * + * + * @param repositoryHandler + */ + @Inject + public GitConfigResource(GitRepositoryHandler repositoryHandler) + { + this.repositoryHandler = repositoryHandler; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + @GET + public GitConfig getConfig() + { + GitConfig config = repositoryHandler.getConfig(); + + if (config == null) + { + config = new GitConfig(); + repositoryHandler.setConfig(config); + } + + return config; + } + + //~--- set methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param uriInfo + * @param config + * + * @return + */ + @POST + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public Response setConfig(@Context UriInfo uriInfo, GitConfig config) + { + repositoryHandler.setConfig(config); + repositoryHandler.storeConfig(); + + return Response.created(uriInfo.getRequestUri()).build(); + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private GitRepositoryHandler repositoryHandler; +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitChangesetViewer.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitChangesetViewer.java new file mode 100644 index 0000000000..9e03615fd6 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitChangesetViewer.java @@ -0,0 +1,305 @@ +/** + * 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.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.NoHeadException; +import org.eclipse.jgit.diff.DiffEntry; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.treewalk.EmptyTreeIterator; +import org.eclipse.jgit.treewalk.TreeWalk; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; +import java.io.IOException; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * + * @author Sebastian Sdorra + */ +public class GitChangesetViewer implements ChangesetViewer +{ + + /** Field description */ + public static final int ID_LENGTH = 20; + + /** the logger for GitChangesetViewer */ + private static final Logger logger = + LoggerFactory.getLogger(GitChangesetViewer.class); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param handler + * @param repository + */ + public GitChangesetViewer(GitRepositoryHandler handler, Repository repository) + { + this.handler = handler; + this.repository = repository; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param start + * @param max + * + * @return + */ + @Override + public ChangesetPagingResult getChangesets(int start, int max) + { + ChangesetPagingResult changesets = null; + File directory = handler.getDirectory(repository); + org.eclipse.jgit.lib.Repository gr = null; + TreeWalk treeWalk = null; + + try + { + gr = GitUtil.open(directory); + + if (!gr.getAllRefs().isEmpty()) + { + Git git = new Git(gr); + List changesetList = new ArrayList(); + int counter = 0; + + treeWalk = new TreeWalk(gr); + + Map tags = createTagMap(gr); + + for (RevCommit commit : git.log().call()) + { + if ((counter >= start) && (counter < start + max)) + { + changesetList.add(createChangeset(treeWalk, tags, commit)); + } + + counter++; + } + + changesets = new ChangesetPagingResult(counter, changesetList); + } + } + catch (NoHeadException ex) + { + logger.error("could not read changesets", ex); + } + catch (IOException ex) + { + logger.error("could not open repository", ex); + } + finally + { + GitUtil.release(treeWalk); + GitUtil.close(gr); + } + + return changesets; + } + + //~--- methods -------------------------------------------------------------- + + /** + * TODO: copy and rename + * + * + * @param modifications + * @param entry + */ + private void appendModification(Modifications modifications, DiffEntry entry) + { + switch (entry.getChangeType()) + { + case ADD : + modifications.getAdded().add(entry.getNewPath()); + + break; + + case MODIFY : + modifications.getModified().add(entry.getNewPath()); + + break; + + case DELETE : + modifications.getRemoved().add(entry.getOldPath()); + + break; + } + } + + /** + * Method description + * + * + * + * @param treeWalk + * @param tags + * @param commit + * + * @return + * + * @throws IOException + */ + private Changeset createChangeset(TreeWalk treeWalk, + Map tags, + RevCommit commit) + throws IOException + { + String id = commit.getId().abbreviate(ID_LENGTH).name(); + long date = GitUtil.getCommitTime(commit); + PersonIdent authorIndent = commit.getCommitterIdent(); + Person author = new Person(authorIndent.getName(), + authorIndent.getEmailAddress()); + String message = commit.getShortMessage(); + Changeset changeset = new Changeset(id, date, author, message); + Modifications modifications = createModifications(treeWalk, commit); + + if (modifications != null) + { + changeset.setModifications(modifications); + } + + String tag = tags.get(commit.getId()); + + if (tag != null) + { + changeset.getTags().add(tag); + } + + return changeset; + } + + /** + * Method description + * + * + * @param treeWalk + * @param commit + * + * @return + * + * @throws IOException + */ + private Modifications createModifications(TreeWalk treeWalk, RevCommit commit) + throws IOException + { + Modifications modifications = null; + + treeWalk.reset(); + treeWalk.setRecursive(true); + + if (commit.getParentCount() > 0) + { + treeWalk.addTree(commit.getParent(0).getTree()); + } + else + { + treeWalk.addTree(new EmptyTreeIterator()); + } + + treeWalk.addTree(commit.getTree()); + + List entries = DiffEntry.scan(treeWalk); + + for (DiffEntry e : entries) + { + if (!e.getOldId().equals(e.getNewId())) + { + if (modifications == null) + { + modifications = new Modifications(); + } + + appendModification(modifications, e); + } + } + + return modifications; + } + + /** + * Method description + * + * + * @param repository + * + * @return + */ + private Map createTagMap(org.eclipse.jgit.lib.Repository repository) + { + Map tagMap = new HashMap(); + Map tags = repository.getTags(); + + if (tags != null) + { + for (Map.Entry e : tags.entrySet()) + { + tagMap.put(e.getValue().getObjectId(), e.getKey()); + } + } + + return tagMap; + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private GitRepositoryHandler handler; + + /** Field description */ + private Repository repository; +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitConfig.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitConfig.java new file mode 100644 index 0000000000..9f508effe6 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitConfig.java @@ -0,0 +1,45 @@ +/** + * 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 GitConfig extends SimpleRepositoryConfig {} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryBrowser.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryBrowser.java new file mode 100644 index 0000000000..6969d9b136 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryBrowser.java @@ -0,0 +1,338 @@ +/** + * 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.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectLoader; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevTree; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.treewalk.TreeWalk; +import org.eclipse.jgit.treewalk.filter.AndTreeFilter; +import org.eclipse.jgit.treewalk.filter.PathFilter; +import org.eclipse.jgit.treewalk.filter.TreeFilter; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import sonia.scm.util.Util; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author Sebastian Sdorra + */ +public class GitRepositoryBrowser implements RepositoryBrowser +{ + + /** the logger for GitRepositoryBrowser */ + private static final Logger logger = + LoggerFactory.getLogger(GitRepositoryBrowser.class); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param handler + * @param repository + */ + public GitRepositoryBrowser(GitRepositoryHandler handler, + Repository repository) + { + this.handler = handler; + this.repository = repository; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param revision + * @param path + * @param output + * + * + * @throws IOException + * @throws RepositoryException + */ + @Override + public void getContent(String revision, String path, OutputStream output) + throws IOException, RepositoryException + { + File directory = handler.getDirectory(repository); + org.eclipse.jgit.lib.Repository repo = GitUtil.open(directory); + TreeWalk treeWalk = null; + RevWalk revWalk = null; + + try + { + treeWalk = new TreeWalk(repo); + treeWalk.setRecursive(Util.nonNull(path).contains("/")); + + ObjectId revId = GitUtil.getRevisionId(repo, revision); + + revWalk = new RevWalk(repo); + + RevCommit entry = revWalk.parseCommit(revId); + RevTree revTree = entry.getTree(); + + treeWalk.addTree(revTree); + treeWalk.setFilter(PathFilter.create(path)); + + if (treeWalk.next()) + { + + // Path exists + if (treeWalk.getFileMode(0).getObjectType() == Constants.OBJ_BLOB) + { + ObjectId blobId = treeWalk.getObjectId(0); + ObjectLoader loader = repo.open(blobId); + + loader.copyTo(output); + } + else + { + + // Not a blob, its something else (tree, gitlink) + throw new PathNotFoundException(path); + } + } + else + { + throw new PathNotFoundException(path); + } + } + finally + { + GitUtil.release(revWalk); + GitUtil.release(treeWalk); + GitUtil.close(repo); + } + } + + /** + * Method description + * + * + * @param revision + * @param path + * + * @return + * + * @throws IOException + * @throws RepositoryException + */ + @Override + public BrowserResult getResult(String revision, String path) + throws IOException, RepositoryException + { + BrowserResult result = null; + File directory = handler.getDirectory(repository); + org.eclipse.jgit.lib.Repository repo = GitUtil.open(directory); + RevWalk revWalk = null; + TreeWalk treeWalk = null; + + try + { + ObjectId revId = GitUtil.getRevisionId(repo, revision); + + treeWalk = new TreeWalk(repo); + revWalk = new RevWalk(repo); + treeWalk.addTree(revWalk.parseTree(revId)); + result = new BrowserResult(); + + List files = new ArrayList(); + + if (Util.isEmpty(path)) + { + while (treeWalk.next()) + { + files.add(createFileObject(repo, revId, treeWalk)); + } + } + else + { + String[] parts = path.split("/"); + int current = 0; + int limit = parts.length; + + while (treeWalk.next()) + { + String name = treeWalk.getNameString(); + + if (current >= limit) + { + String p = treeWalk.getPathString(); + + if (p.split("/").length > limit) + { + files.add(createFileObject(repo, revId, treeWalk)); + } + } + else if (name.equalsIgnoreCase(parts[current])) + { + current++; + treeWalk.enterSubtree(); + } + } + } + + result.setFiles(files); + result.setRevision(revId.getName()); + } + finally + { + GitUtil.close(repo); + GitUtil.release(revWalk); + GitUtil.release(treeWalk); + } + + return result; + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * + * + * @param repo + * @param revId + * @param treeWalk + * + * @return + * + * @throws IOException + */ + private FileObject createFileObject(org.eclipse.jgit.lib.Repository repo, + ObjectId revId, TreeWalk treeWalk) + throws IOException + { + FileObject file = new FileObject(); + String path = treeWalk.getPathString(); + + file.setName(treeWalk.getNameString()); + file.setPath(path); + + ObjectLoader loader = repo.open(treeWalk.getObjectId(0)); + + file.setDirectory(loader.getType() == Constants.OBJ_TREE); + file.setLength(loader.getSize()); + + // don't show message and date for directories to improve performance + if (!file.isDirectory()) + { + RevCommit commit = getLatestCommit(repo, revId, path); + + if (commit != null) + { + file.setLastModified(GitUtil.getCommitTime(commit)); + file.setDescription(commit.getShortMessage()); + } + else if (logger.isWarnEnabled()) + { + logger.warn("could not find latest commit for {} on {}", path, revId); + } + } + + return file; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * + * @param repo + * @param revId + * @param path + * + * @return + */ + private RevCommit getLatestCommit(org.eclipse.jgit.lib.Repository repo, + ObjectId revId, String path) + { + RevCommit result = null; + RevWalk walk = null; + + try + { + walk = new RevWalk(repo); + walk.setTreeFilter(AndTreeFilter.create(PathFilter.create(path), + TreeFilter.ANY_DIFF)); + + RevCommit commit = walk.parseCommit(revId); + + walk.markStart(commit); + result = Util.getFirst(walk); + } + catch (Exception ex) + { + logger.error("could not parse commit for file", ex); + } + finally + { + GitUtil.release(walk); + } + + return result; + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private GitRepositoryHandler handler; + + /** Field description */ + private Repository repository; +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryHandler.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryHandler.java new file mode 100644 index 0000000000..0b2dfa2b55 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryHandler.java @@ -0,0 +1,208 @@ +/** + * 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 org.eclipse.jgit.storage.file.FileRepository; +import org.eclipse.jgit.storage.file.FileRepositoryBuilder; + +import sonia.scm.Type; +import sonia.scm.io.FileSystem; +import sonia.scm.plugin.ext.Extension; +import sonia.scm.store.StoreFactory; +import sonia.scm.util.AssertUtil; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; +import java.io.IOException; + +/** + * + * @author Sebastian Sdorra + */ +@Singleton +@Extension +public class GitRepositoryHandler + extends AbstractSimpleRepositoryHandler +{ + + /** Field description */ + public static final String TYPE_DISPLAYNAME = "Git"; + + /** Field description */ + public static final String TYPE_NAME = "git"; + + /** Field description */ + public static final Type TYPE = new Type(TYPE_NAME, TYPE_DISPLAYNAME); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param storeFactory + * @param fileSystem + */ + @Inject + public GitRepositoryHandler(StoreFactory storeFactory, FileSystem fileSystem) + { + super(storeFactory, fileSystem); + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param repository + * + * @return + */ + @Override + public ChangesetViewer getChangesetViewer(Repository repository) + { + GitChangesetViewer changesetViewer = null; + + AssertUtil.assertIsNotNull(repository); + + String type = repository.getType(); + + AssertUtil.assertIsNotEmpty(type); + + if (TYPE_NAME.equals(type)) + { + changesetViewer = new GitChangesetViewer(this, repository); + } + else + { + throw new IllegalArgumentException("mercurial repository is required"); + } + + return changesetViewer; + } + + /** + * Method description + * + * + * @param repository + * + * @return + */ + @Override + public RepositoryBrowser getRepositoryBrowser(Repository repository) + { + AssertUtil.assertIsNotNull(repository); + + return new GitRepositoryBrowser(this, repository); + } + + /** + * Method description + * + * + * @return + */ + @Override + public Type getType() + { + return TYPE; + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param repository + * @param directory + * + * @throws IOException + * @throws RepositoryException + */ + @Override + protected void create(Repository repository, File directory) + throws RepositoryException, IOException + { + FileRepository fr = null; + + try + { + fr = new FileRepositoryBuilder().setGitDir( + directory).readEnvironment().findGitDir().build(); + fr.create(true); + } + finally + { + if (fr != null) + { + fr.close(); + } + } + } + + /** + * Method description + * + * + * @return + */ + @Override + protected GitConfig createInitialConfig() + { + return new GitConfig(); + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + @Override + protected Class getConfigClass() + { + return GitConfig.class; + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java new file mode 100644 index 0000000000..231dc9e840 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java @@ -0,0 +1,167 @@ +/** + * 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 java.io.File; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.treewalk.TreeWalk; + +import sonia.scm.util.Util; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.IOException; +import org.eclipse.jgit.lib.RepositoryCache; +import org.eclipse.jgit.util.FS; + +/** + * + * @author Sebastian Sdorra + */ +public class GitUtil +{ + + /** + * Method description + * + * + * @param repo + */ + public static void close(org.eclipse.jgit.lib.Repository repo) + { + if (repo != null) + { + repo.close(); + } + } + + /** + * Method description + * + * + * @param walk + */ + public static void release(TreeWalk walk) + { + if (walk != null) + { + walk.release(); + } + } + + /** + * Method description + * + * + * @param walk + */ + public static void release(RevWalk walk) + { + if (walk != null) + { + walk.release(); + } + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param commit + * + * @return + */ + public static long getCommitTime(RevCommit commit) + { + long date = commit.getCommitTime(); + + date = date * 1000; + + return date; + } + + + /** + * Method description + * + * + * @param directory + * + * @return + * + * @throws IOException + */ + public static org.eclipse.jgit.lib.Repository open(File directory) + throws IOException + { + return RepositoryCache.open(RepositoryCache.FileKey.lenient(directory, + FS.DETECTED), true); + } + + /** + * Method description + * + * + * @param repo + * @param revision + * + * @return + * + * @throws IOException + */ + public static ObjectId getRevisionId(org.eclipse.jgit.lib.Repository repo, + String revision) + throws IOException + { + ObjectId revId = null; + + if (Util.isNotEmpty(revision)) + { + revId = repo.resolve(revision); + } + else + { + revId = repo.resolve(Constants.HEAD); + } + + return revId; + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java new file mode 100644 index 0000000000..6c1181021e --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java @@ -0,0 +1,121 @@ +/** + * 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.GitRepositoryHandler; +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 GitPermissionFilter extends RegexPermissionFilter +{ + + /** Field description */ + public static final String PARAMETER_SERVICE = "service"; + + /** Field description */ + public static final String PARAMETER_VALUE_RECEIVE = "git-receive-pack"; + + /** Field description */ + public static final String URI_RECEIVE_PACK = "git-receive-pack"; + + /** Field description */ + public static final String URI_REF_INFO = "/info/refs"; + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * + * @param securityContextProvider + * @param repositoryManager + */ + @Inject + public GitPermissionFilter( + Provider securityContextProvider, + RepositoryManager repositoryManager) + { + super(securityContextProvider, repositoryManager); + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + @Override + protected String getType() + { + return GitRepositoryHandler.TYPE_NAME; + } + + /** + * Method description + * + * + * @param request + * + * @return + */ + @Override + protected boolean isWriteRequest(HttpServletRequest request) + { + String uri = request.getRequestURI(); + + return uri.endsWith(URI_RECEIVE_PACK) + || (uri.endsWith(URI_REF_INFO) + && PARAMETER_VALUE_RECEIVE.equals( + request.getParameter(PARAMETER_SERVICE))); + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitRepositoryResolver.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitRepositoryResolver.java new file mode 100644 index 0000000000..4516e12d53 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitRepositoryResolver.java @@ -0,0 +1,210 @@ +/** + * 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.lib.Repository; +import org.eclipse.jgit.lib.RepositoryCache; +import org.eclipse.jgit.lib.RepositoryCache.FileKey; +import org.eclipse.jgit.transport.resolver.RepositoryResolver; +import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException; +import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException; +import org.eclipse.jgit.util.FS; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import sonia.scm.repository.GitConfig; +import sonia.scm.repository.GitRepositoryHandler; + +//~--- 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 handler + */ + public GitRepositoryResolver(GitRepositoryHandler handler) + { + this.handler = handler; + } + + //~--- 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 + { + GitConfig config = handler.getConfig(); + + if (config.isValid()) + { + File gitdir = new File(config.getRepositoryDirectory(), repositoryName); + + if (logger.isDebugEnabled()) + { + logger.debug("try to open git repository at {}", gitdir); + } + + if (!gitdir.exists()) + { + throw new RepositoryNotFoundException(repositoryName); + } + + repository = RepositoryCache.open(FileKey.lenient(gitdir, FS.DETECTED), + true); + } + else + { + if (logger.isWarnEnabled()) + { + logger.warn("gitconfig is not valid, the service is not available"); + } + + throw new ServiceNotEnabledException(); + } + } + catch (RuntimeException e) + { + throw new RepositoryNotFoundException(repositoryName, e); + } + catch (IOException e) + { + throw new RepositoryNotFoundException(repositoryName, e); + } + + return repository; + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private GitRepositoryHandler handler; +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitRepositoryViewer.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitRepositoryViewer.java new file mode 100644 index 0000000000..c1ce6e91aa --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitRepositoryViewer.java @@ -0,0 +1,205 @@ +/** + * 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.apache.commons.lang.StringEscapeUtils; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.NoHeadException; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; + +import sonia.scm.io.RegexResourceProcessor; +import sonia.scm.io.ResourceProcessor; +import sonia.scm.util.IOUtil; +import sonia.scm.util.Util; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; + +import java.util.Date; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletResponse; + +/** + * + * @author Sebastian Sdorra + */ +public class GitRepositoryViewer +{ + + /** Field description */ + public static final String MIMETYPE_HTML = "text/html"; + + /** Field description */ + public static final String RESOURCE_GITINDEX = "/sonia/scm/git.index.html"; + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param response + * @param repository + * @param repositoryName + * + * @throws IOException + * @throws NoHeadException + * @throws ServletException + */ + public void handleRequest(HttpServletResponse response, + Repository repository, String repositoryName) + throws IOException, ServletException, NoHeadException + { + response.setContentType(MIMETYPE_HTML); + + ResourceProcessor processor = new RegexResourceProcessor(); + + processor.addVariable("name", repositoryName); + + StringBuilder sb = new StringBuilder(); + + if (!repository.getAllRefs().isEmpty()) + { + Git git = new Git(repository); + int c = 0; + + for (RevCommit commit : git.log().call()) + { + appendCommit(sb, commit); + c++; + + if (c > logSize) + { + break; + } + } + } + + processor.addVariable("commits", sb.toString()); + + BufferedReader reader = null; + PrintWriter writer = null; + + try + { + reader = new BufferedReader( + new InputStreamReader( + GitRepositoryViewer.class.getResourceAsStream( + RESOURCE_GITINDEX))); + writer = response.getWriter(); + processor.process(reader, writer); + } + finally + { + IOUtil.close(reader); + IOUtil.close(writer); + } + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + public int getLogSize() + { + return logSize; + } + + //~--- set methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param logSize + */ + public void setLogSize(int logSize) + { + this.logSize = logSize; + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param sb + * @param commit + */ + private void appendCommit(StringBuilder sb, RevCommit commit) + { + sb.append(""); + + long time = commit.getCommitTime(); + + sb.append(Util.formatDate(new Date(time * 1000))); + sb.append(""); + + PersonIdent person = commit.getCommitterIdent(); + + if (person != null) + { + String name = person.getName(); + + if (Util.isNotEmpty(name)) + { + sb.append(StringEscapeUtils.escapeHtml(name)); + } + } + + sb.append(""); + sb.append(StringEscapeUtils.escapeHtml(commit.getFullMessage())); + sb.append(""); + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private int logSize = 25; +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java new file mode 100644 index 0000000000..327d18415b --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.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 GitServletModule extends ServletModule +{ + + /** Field description */ + public static final String PATTERN_GIT = "/git/*"; + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + */ + @Override + protected void configureServlets() + { + filter(PATTERN_GIT).through(BasicAuthenticationFilter.class); + filter(PATTERN_GIT).through(GitPermissionFilter.class); + serve(PATTERN_GIT).with(ScmGitServlet.class); + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServlet.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServlet.java new file mode 100644 index 0000000000..1efac88ef7 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServlet.java @@ -0,0 +1,176 @@ +/** + * 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.eclipse.jgit.http.server.GitServlet; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.transport.resolver.RepositoryResolver; + +import sonia.scm.repository.GitRepositoryHandler; +import sonia.scm.util.HttpUtil; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.IOException; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * + * @author Sebastian Sdorra + */ +@Singleton +public class ScmGitServlet extends GitServlet +{ + + /** Field description */ + public static final String REGEX_GITHTTPBACKEND = + "(?x)^/git/(.*/(HEAD|info/refs|objects/(info/[^/]+|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\\.(pack|idx))|git-(upload|receive)-pack))$"; + + /** Field description */ + private static final long serialVersionUID = -7712897339207470674L; + + /** Field description */ + private static final Pattern REGEX_REPOSITORYNAME = + Pattern.compile("/git/([^/]+)/?.*"); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param handler + */ + @Inject + public ScmGitServlet(GitRepositoryHandler handler) + { + resolver = new GitRepositoryResolver(handler); + setRepositoryResolver(resolver); + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param request + * @param response + * + * @throws IOException + * @throws ServletException + */ + @Override + protected void service(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException + { + String uri = HttpUtil.getStrippedURI(request); + + if (uri.matches(REGEX_GITHTTPBACKEND)) + { + super.service(request, response); + } + else + { + printGitInformation(request, response); + } + } + + /** + * Method description + * + * + * + * @param request + * @param response + * + * @throws IOException + * @throws ServletException + */ + private void printGitInformation(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException + { + String uri = HttpUtil.getStrippedURI(request); + Matcher m = REGEX_REPOSITORYNAME.matcher(uri); + String name = null; + Repository repository = null; + + try + { + if (m.matches()) + { + name = m.group(1); + repository = resolver.open(request, name); + } + + if (repository != null) + { + new GitRepositoryViewer().handleRequest(response, repository, name); + } + else + { + response.sendError(HttpServletResponse.SC_NOT_FOUND); + } + } + catch (Exception ex) + { + throw new ServletException(ex); + } + finally + { + if (repository != null) + { + repository.close(); + } + } + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private RepositoryResolver resolver; +} diff --git a/scm-plugins/scm-git-plugin/src/main/resources/META-INF/scm/plugin.xml b/scm-plugins/scm-git-plugin/src/main/resources/META-INF/scm/plugin.xml new file mode 100644 index 0000000000..798c2298e0 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/resources/META-INF/scm/plugin.xml @@ -0,0 +1,63 @@ + + + + + + + + + ${project.groupId} + ${project.artifactId} + ${project.version} + ${project.name} + ${project.description} + Sebastian Sdorra + ${project.url} + + + + 1.1 + + + + + + + diff --git a/scm-plugins/scm-git-plugin/src/main/resources/sonia/scm/git.config.js b/scm-plugins/scm-git-plugin/src/main/resources/sonia/scm/git.config.js new file mode 100644 index 0000000000..52e79734f2 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/resources/sonia/scm/git.config.js @@ -0,0 +1,97 @@ +/* + * 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 + * + */ + +Ext.ns("Sonia.git"); + +Sonia.git.ConfigPanel = Ext.extend(Sonia.config.SimpleConfigForm, { + + // labels + titleText: 'Git Settings', + repositoryDirectoryText: 'Repository directory', + + // helpTexts + repositoryDirectoryHelpText: 'Location of the Git repositories.', + + initComponent: function(){ + + var config = { + title : this.titleText, + configUrl: restUrl + 'config/repositories/git.json', + items : [{ + xtype: 'textfield', + name: 'repositoryDirectory', + fieldLabel: this.repositoryDirectoryText, + helpText: this.repositoryDirectoryHelpText, + allowBlank : false + }] + } + + Ext.apply(this, Ext.apply(this.initialConfig, config)); + Sonia.git.ConfigPanel.superclass.initComponent.apply(this, arguments); + } + +}); + +Ext.reg("gitConfigPanel", Sonia.git.ConfigPanel); + +// i18n + +if ( i18n != null && i18n.country == 'de' ){ + + Ext.override(Sonia.git.ConfigPanel, { + + // labels + titleText: 'Git Einstellungen', + repositoryDirectoryText: 'Repository-Verzeichnis', + + // helpTexts + repositoryDirectoryHelpText: 'Verzeichnis der Git-Repositories.' + + }); + +} + +// register information panel + +initCallbacks.push(function(main){ + main.registerInfoPanel('git', { + checkoutTemplate: 'git clone {0}', + xtype: 'repositoryExtendedInfoPanel' + }); +}); + + + +// register panel + +registerConfigPanel({ + xtype : 'gitConfigPanel' +}); diff --git a/scm-plugins/scm-git-plugin/src/main/resources/sonia/scm/git.index.html b/scm-plugins/scm-git-plugin/src/main/resources/sonia/scm/git.index.html new file mode 100644 index 0000000000..cc9e84c230 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/resources/sonia/scm/git.index.html @@ -0,0 +1,114 @@ + + + + + SCM :: Manager - Git Repository - ${name} + + + + +

SCM :: Manager - Git Repository - ${name}

+ + + + + + + + + + + ${commits} + +
TimeAuthorMessage
+ +

Git Informations

+ + + + \ No newline at end of file diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryHandlerTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryHandlerTest.java new file mode 100644 index 0000000000..eb9646ffe8 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryHandlerTest.java @@ -0,0 +1,104 @@ +/** + * 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 sonia.scm.io.DefaultFileSystem; +import sonia.scm.store.StoreFactory; + +import static org.junit.Assert.*; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; + +/** + * + * @author Sebastian Sdorra + */ +public class GitRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase +{ + + /** + * Method description + * + * + * @param directory + */ + @Override + protected void checkDirectory(File directory) + { + File head = new File(directory, "HEAD"); + + assertTrue(head.exists()); + assertTrue(head.isFile()); + + File config = new File(directory, "config"); + + assertTrue(config.exists()); + assertTrue(config.isFile()); + + File refs = new File(directory, "refs"); + + assertTrue(refs.exists()); + assertTrue(refs.isDirectory()); + } + + /** + * Method description + * + * + * @param factory + * @param directory + * + * @return + */ + @Override + protected RepositoryHandler createRepositoryHandler(StoreFactory factory, + File directory) + { + GitRepositoryHandler repositoryHandler = new GitRepositoryHandler(factory, + new DefaultFileSystem()); + + repositoryHandler.init(contextProvider); + + GitConfig config = new GitConfig(); + + config.setRepositoryDirectory(directory); + repositoryHandler.setConfig(config); + + return repositoryHandler; + } +} diff --git a/scm-plugins/scm-hg-plugin/pom.xml b/scm-plugins/scm-hg-plugin/pom.xml new file mode 100644 index 0000000000..a635c9e2fa --- /dev/null +++ b/scm-plugins/scm-hg-plugin/pom.xml @@ -0,0 +1,56 @@ + + + + 4.0.0 + + + sonia.scm.plugins + scm-plugins + 1.5-SNAPSHOT + + + sonia.scm.plugins + scm-hg-plugin + 1.5-SNAPSHOT + scm-hg-plugin + https://bitbucket.org/sdorra/scm-manager + Plugin for the version control system Mercurial + + + + + javax.servlet + servlet-api + ${servlet.version} + provided + + + + com.sun.jersey + jersey-json + ${jersey.version} + + + + + + sonia.scm + scm-test + 1.5-SNAPSHOT + test + + + + + + + + maven.scm-manager.org + scm-manager release repository + http://maven.scm-manager.org/nexus/content/groups/public + + + + + diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/rest/resources/HgConfigResource.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/rest/resources/HgConfigResource.java new file mode 100644 index 0000000000..2f43505f7e --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/rest/resources/HgConfigResource.java @@ -0,0 +1,351 @@ +/** + * 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.SCMContext; +import sonia.scm.cache.CacheManager; +import sonia.scm.installer.HgInstallerFactory; +import sonia.scm.installer.HgPackage; +import sonia.scm.installer.HgPackageReader; +import sonia.scm.installer.HgPackages; +import sonia.scm.net.HttpClient; +import sonia.scm.repository.HgConfig; +import sonia.scm.repository.HgRepositoryHandler; +import sonia.scm.web.HgWebConfigWriter; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.IOException; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +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; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * + * @author Sebastian Sdorra + */ +@Singleton +@Path("config/repositories/hg") +public class HgConfigResource +{ + + /** + * Constructs ... + * + * + * + * + * @param client + * @param handler + * @param cacheManager + */ + @Inject + public HgConfigResource(HttpClient client, HgRepositoryHandler handler, + CacheManager cacheManager) + { + this.client = client; + this.handler = handler; + this.pkgReader = new HgPackageReader(cacheManager); + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param uriInfo + * + * @return + */ + @POST + @Path("auto-configuration") + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public HgConfig autoConfiguration(@Context UriInfo uriInfo) + { + return autoConfiguration(uriInfo, null); + } + + /** + * Method description + * + * + * @param uriInfo + * @param config + * + * @return + */ + @POST + @Path("auto-configuration") + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public HgConfig autoConfiguration(@Context UriInfo uriInfo, HgConfig config) + { + if (config == null) + { + config = new HgConfig(); + } + + handler.doAutoConfiguration(config); + + return handler.getConfig(); + } + + /** + * Method description + * + * + * + * @param id + * @return + */ + @POST + @Path("packages/{pkgId}") + public Response installPackage(@PathParam("pkgId") String id) + { + Response response = null; + HgPackage pkg = pkgReader.getPackage(id); + + if (pkg != null) + { + if (HgInstallerFactory.createInstaller().installPackage(client, handler, + SCMContext.getContext().getBaseDirectory(), pkg)) + { + response = Response.noContent().build(); + } + else + { + response = + Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); + } + } + else + { + response = Response.status(Response.Status.NOT_FOUND).build(); + } + + return response; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + @GET + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public HgConfig getConfig() + { + HgConfig config = handler.getConfig(); + + if (config == null) + { + config = new HgConfig(); + } + + return config; + } + + /** + * Method description + * + * + * @return + */ + @GET + @Path("installations/hg") + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public InstallationsResponse getHgInstallations() + { + List installations = + HgInstallerFactory.createInstaller().getHgInstallations(); + + return new InstallationsResponse(installations); + } + + /** + * Method description + * + * + * @return + */ + @GET + @Path("packages") + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public HgPackages getPackages() + { + return pkgReader.getPackages(); + } + + /** + * Method description + * + * + * @return + */ + @GET + @Path("installations/python") + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public InstallationsResponse getPythonInstallations() + { + List installations = + HgInstallerFactory.createInstaller().getPythonInstallations(); + + return new InstallationsResponse(installations); + } + + //~--- 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, HgConfig config) + throws IOException + { + handler.setConfig(config); + handler.storeConfig(); + new HgWebConfigWriter(config).write(); + + return Response.created(uriInfo.getRequestUri()).build(); + } + + //~--- inner classes -------------------------------------------------------- + + /** + * Class description + * + * + * @version Enter version here..., 11/04/25 + * @author Enter your name here... + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlRootElement(name = "installations") + public static class InstallationsResponse + { + + /** + * Constructs ... + * + */ + public InstallationsResponse() {} + + /** + * Constructs ... + * + * + * @param paths + */ + public InstallationsResponse(List paths) + { + this.paths = paths; + } + + //~--- get methods -------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + public List getPaths() + { + return paths; + } + + //~--- set methods -------------------------------------------------------- + + /** + * Method description + * + * + * @param paths + */ + public void setPaths(List paths) + { + this.paths = paths; + } + + //~--- fields ------------------------------------------------------------- + + /** Field description */ + @XmlElement(name = "path") + private List paths; + } + + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private HttpClient client; + + /** Field description */ + private HgRepositoryHandler handler; + + /** Field description */ + private HgPackageReader pkgReader; +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/AbstractHgInstaller.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/AbstractHgInstaller.java new file mode 100644 index 0000000000..637825a407 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/AbstractHgInstaller.java @@ -0,0 +1,102 @@ +/** + * 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.installer; + +//~--- non-JDK imports -------------------------------------------------------- + +import sonia.scm.net.HttpClient; +import sonia.scm.repository.HgConfig; +import sonia.scm.repository.HgRepositoryHandler; +import sonia.scm.util.IOUtil; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; +import java.io.IOException; + +/** + * + * @author Sebastian Sdorra + */ +public abstract class AbstractHgInstaller implements HgInstaller +{ + + /** Field description */ + public static final String DIRECTORY_REPOSITORY = "repositories"; + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * + * @param baseDirectory + * @param config + * + * @throws IOException + */ + @Override + public void install(File baseDirectory, HgConfig config) throws IOException + { + File repoDirectory = new File( + baseDirectory, + DIRECTORY_REPOSITORY.concat(File.separator).concat( + HgRepositoryHandler.TYPE_NAME)); + + IOUtil.mkdirs(repoDirectory); + config.setRepositoryDirectory(repoDirectory); + } + + /** + * Method description + * + * + * + * + * @param client + * @param handler + * @param baseDirectory + * @param pkg + * + * @return + */ + @Override + public boolean installPackage(HttpClient client, HgRepositoryHandler handler, + File baseDirectory, HgPackage pkg) + { + return new HgPackageInstaller(client, handler, baseDirectory, + pkg).install(); + } +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgInstaller.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgInstaller.java new file mode 100644 index 0000000000..219ce5204e --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgInstaller.java @@ -0,0 +1,113 @@ +/** + * 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.installer; + +//~--- non-JDK imports -------------------------------------------------------- + +import sonia.scm.net.HttpClient; +import sonia.scm.repository.HgConfig; +import sonia.scm.repository.HgRepositoryHandler; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; +import java.io.IOException; + +import java.util.List; + +/** + * + * @author Sebastian Sdorra + */ +public interface HgInstaller +{ + + /** + * Method description + * + * + * + * @param baseDirectory + * @param config + * + * @throws IOException + */ + public void install(File baseDirectory, HgConfig config) throws IOException; + + /** + * Method description + * + * + * + * + * @param client + * @param handler + * @param baseDirectory + * @param pkg + * + * @return + */ + public boolean installPackage(HttpClient client, HgRepositoryHandler handler, + File baseDirectory, HgPackage pkg); + + /** + * Method description + * + * + * + * @param baseDirectory + * @param config + * + * @throws IOException + */ + public void update(File baseDirectory, HgConfig config) throws IOException; + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + public List getHgInstallations(); + + /** + * Method description + * + * + * @return + */ + public List getPythonInstallations(); +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgInstallerFactory.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgInstallerFactory.java new file mode 100644 index 0000000000..588cb55f12 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgInstallerFactory.java @@ -0,0 +1,68 @@ +/** + * 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.installer; + +//~--- non-JDK imports -------------------------------------------------------- + +import sonia.scm.util.SystemUtil; + +/** + * + * @author Sebastian Sdorra + */ +public class HgInstallerFactory +{ + + /** + * Method description + * + * + * @return + */ + public static HgInstaller createInstaller() + { + HgInstaller installer = null; + + if (SystemUtil.isWindows()) + { + installer = new WindowsHgInstaller(); + } + else + { + installer = new UnixHgInstaller(); + } + + return installer; + } +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgPackage.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgPackage.java new file mode 100644 index 0000000000..6bd5a416a6 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgPackage.java @@ -0,0 +1,262 @@ +/** + * 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.installer; + +//~--- non-JDK imports -------------------------------------------------------- + +import sonia.scm.repository.HgConfig; + +//~--- JDK imports ------------------------------------------------------------ + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * + * @author Sebastian Sdorra + */ +@XmlRootElement(name = "package") +@XmlAccessorType(XmlAccessType.FIELD) +public class HgPackage +{ + + /** + * Method description + * + * + * @return + */ + public String getArch() + { + return arch; + } + + /** + * Method description + * + * + * @return + */ + public HgConfig getHgConfigTemplate() + { + return hgConfigTemplate; + } + + /** + * Method description + * + * + * @return + */ + public String getHgVersion() + { + return hgVersion; + } + + /** + * Method description + * + * + * @return + */ + public String getId() + { + return id; + } + + /** + * Method description + * + * + * @return + */ + public String getPlatform() + { + return platform; + } + + /** + * Method description + * + * + * @return + */ + public String getPythonVersion() + { + return pythonVersion; + } + + /** + * Method description + * + * + * @return + */ + public long getSize() + { + return size; + } + + /** + * Method description + * + * + * @return + */ + public String getUrl() + { + return url; + } + + //~--- set methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param arch + */ + public void setArch(String arch) + { + this.arch = arch; + } + + /** + * Method description + * + * + * @param hgConfigTemplate + */ + public void setHgConfigTemplate(HgConfig hgConfigTemplate) + { + this.hgConfigTemplate = hgConfigTemplate; + } + + /** + * Method description + * + * + * @param hgVersion + */ + public void setHgVersion(String hgVersion) + { + this.hgVersion = hgVersion; + } + + /** + * Method description + * + * + * @param id + */ + public void setId(String id) + { + this.id = id; + } + + /** + * Method description + * + * + * @param platform + */ + public void setPlatform(String platform) + { + this.platform = platform; + } + + /** + * Method description + * + * + * @param pythonVersion + */ + public void setPythonVersion(String pythonVersion) + { + this.pythonVersion = pythonVersion; + } + + /** + * Method description + * + * + * @param size + */ + public void setSize(long size) + { + this.size = size; + } + + /** + * Method description + * + * + * @param url + */ + public void setUrl(String url) + { + this.url = url; + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private String arch; + + /** Field description */ + @XmlElement(name = "hg-config-template") + private HgConfig hgConfigTemplate; + + /** Field description */ + @XmlElement(name = "hg-version") + private String hgVersion; + + /** Field description */ + private String id; + + /** Field description */ + private String platform; + + /** Field description */ + @XmlElement(name = "python-version") + private String pythonVersion; + + /** Field description */ + private long size; + + /** Field description */ + private String url; +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgPackageInstaller.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgPackageInstaller.java new file mode 100644 index 0000000000..558970b67c --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgPackageInstaller.java @@ -0,0 +1,269 @@ +/** + * 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.installer; + +//~--- non-JDK imports -------------------------------------------------------- + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import sonia.scm.io.ZipUnArchiver; +import sonia.scm.net.HttpClient; +import sonia.scm.repository.HgConfig; +import sonia.scm.repository.HgRepositoryHandler; +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; + +import java.text.MessageFormat; + +/** + * + * @author Sebastian Sdorra + */ +public class HgPackageInstaller implements Runnable +{ + + /** the logger for HgPackageInstaller */ + private static final Logger logger = + LoggerFactory.getLogger(HgPackageInstaller.class); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * + * + * @param client + * @param handler + * @param baseDirectory + * @param pkg + */ + public HgPackageInstaller(HttpClient client, HgRepositoryHandler handler, + File baseDirectory, HgPackage pkg) + { + this.client = client; + this.handler = handler; + this.baseDirectory = baseDirectory; + this.pkg = pkg; + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + public boolean install() + { + boolean success = false; + File downloadedFile = downloadFile(); + + if ((downloadedFile != null) && downloadedFile.exists()) + { + File directory = extractPackage(downloadedFile); + + if ((directory != null) && directory.exists()) + { + updateConfig(directory); + success = true; + } + } + + return success; + } + + /** + * Method description + * + */ + @Override + public void run() + { + if (!install()) + { + logger.error("installation of pkg {} failed", pkg.getId()); + } + else if (logger.isInfoEnabled()) + { + logger.info("successfully installed pkg {}", pkg.getId()); + } + } + + /** + * Method description + * + * + * @return + */ + private File downloadFile() + { + File file = null; + InputStream input = null; + OutputStream output = null; + + try + { + file = File.createTempFile("scm-hg-", ".pkg"); + + if (logger.isDebugEnabled()) + { + logger.debug("download package to {}", file.getAbsolutePath()); + } + + // TODO error handling + input = client.get(pkg.getUrl()).getContent(); + output = new FileOutputStream(file); + IOUtil.copy(input, output); + } + catch (IOException ex) + { + logger.error("could not downlaod file ".concat(pkg.getUrl()), ex); + } + finally + { + IOUtil.close(input); + IOUtil.close(output); + } + + return file; + } + + /** + * Method description + * + * + * @param file + * + * @return + */ + private File extractPackage(File file) + { + File directory = new File(baseDirectory, + "pkg".concat(File.separator).concat(pkg.getId())); + + IOUtil.mkdirs(directory); + + try + { + IOUtil.extract(file, directory, ZipUnArchiver.EXTENSION); + } + catch (IOException ex) + { + directory = null; + logger.error("could not extract pacakge ".concat(pkg.getId()), ex); + } + finally + { + + // delete temp file + try + { + IOUtil.delete(file, true); + } + catch (IOException ex) + { + logger.error(ex.getMessage(), ex); + } + } + + return directory; + } + + /** + * Method description + * + * + * @param directory + */ + private void updateConfig(File directory) + { + String path = directory.getAbsolutePath(); + HgConfig template = pkg.getHgConfigTemplate(); + HgConfig config = handler.getConfig(); + + config.setHgBinary(getTemplateValue(template.getHgBinary(), path)); + config.setPythonBinary(getTemplateValue(template.getPythonBinary(), path)); + config.setPythonPath(getTemplateValue(template.getPythonPath(), path)); + config.setUseOptimizedBytecode(template.isUseOptimizedBytecode()); + handler.storeConfig(); + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param template + * @param path + * + * @return + */ + private String getTemplateValue(String template, String path) + { + String result = null; + + if (template != null) + { + result = MessageFormat.format(template, path); + } + + return result; + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private File baseDirectory; + + /** Field description */ + private HttpClient client; + + /** Field description */ + private HgRepositoryHandler handler; + + /** Field description */ + private HgPackage pkg; +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgPackageReader.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgPackageReader.java new file mode 100644 index 0000000000..0bb967bdea --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgPackageReader.java @@ -0,0 +1,254 @@ +/** + * 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.installer; + +//~--- non-JDK imports -------------------------------------------------------- + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import sonia.scm.PlatformType; +import sonia.scm.cache.Cache; +import sonia.scm.cache.CacheManager; +import sonia.scm.util.IOUtil; +import sonia.scm.util.SystemUtil; +import sonia.scm.util.Util; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.IOException; +import java.io.InputStream; + +import java.net.URL; + +import java.util.ArrayList; +import java.util.List; +import java.util.zip.GZIPInputStream; + +import javax.xml.bind.JAXB; + +/** + * + * @author Sebastian Sdorra + */ +public class HgPackageReader +{ + + /** Field description */ + public static final String CACHENAME = "sonia.scm.hg.packages"; + + /** Field description */ + public static final String PACKAGEURL = + "http://download.scm-manager.org/pkg/mercurial/packages.xml.gz"; + + /** the logger for HgPackageReader */ + private static final Logger logger = + LoggerFactory.getLogger(HgPackageReader.class); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param cacheManager + */ + public HgPackageReader(CacheManager cacheManager) + { + cache = cacheManager.getCache(String.class, HgPackages.class, CACHENAME); + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param id + * + * @return + */ + public HgPackage getPackage(String id) + { + HgPackage pkg = null; + + for (HgPackage p : getPackages()) + { + if (id.equals(p.getId())) + { + pkg = p; + + break; + } + } + + return pkg; + } + + /** + * Method description + * + * + * @return + */ + public HgPackages getPackages() + { + HgPackages packages = cache.get(HgPackages.class.getName()); + + if (packages == null) + { + packages = getRemptePackages(); + filterPackage(packages); + cache.put(HgPackages.class.getName(), packages); + } + + return packages; + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param packages + */ + private void filterPackage(HgPackages packages) + { + List pkgList = new ArrayList(); + + for (HgPackage pkg : packages) + { + boolean add = true; + + if (Util.isNotEmpty(pkg.getPlatform())) + { + PlatformType pt = PlatformType.createPlatformType(pkg.getPlatform()); + + if (SystemUtil.getPlatform().getType() != pt) + { + if (logger.isDebugEnabled()) + { + logger.debug("reject package {}, because of wrong platform {}", + pkg.getId(), pkg.getPlatform()); + } + + add = false; + } + } + + if (add && Util.isNotEmpty(pkg.getArch())) + { + if (!SystemUtil.getArch().equals(pkg.getArch())) + { + if (logger.isDebugEnabled()) + { + logger.debug("reject package {}, because of wrong arch {}", + pkg.getId(), pkg.getArch()); + } + + add = false; + } + } + + if (add) + { + if (logger.isDebugEnabled()) + { + logger.debug("added HgPackage {}", pkg.getId()); + } + + pkgList.add(pkg); + } + } + + packages.setPackages(pkgList); + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + private HgPackages getRemptePackages() + { + if (logger.isInfoEnabled()) + { + logger.info("fetch HgPackages from {}", PACKAGEURL); + } + + HgPackages packages = null; + InputStream input = null; + + try + { + URL url = new URL(PACKAGEURL); + + if (PACKAGEURL.endsWith(".gz")) + { + input = new GZIPInputStream(url.openStream()); + } + else + { + input = url.openStream(); + } + + packages = JAXB.unmarshal(input, HgPackages.class); + } + catch (IOException ex) + { + logger.error("could not read HgPackages from {}", PACKAGEURL); + } + finally + { + IOUtil.close(input); + } + + if (packages == null) + { + packages = new HgPackages(); + packages.setPackages(new ArrayList()); + } + + return packages; + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private Cache cache; +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgPackages.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgPackages.java new file mode 100644 index 0000000000..515fac6d9a --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgPackages.java @@ -0,0 +1,98 @@ +/** + * 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.installer; + +//~--- JDK imports ------------------------------------------------------------ + +import java.util.Iterator; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * + * @author Sebastian Sdorra + */ +@XmlRootElement(name = "packages") +@XmlAccessorType(XmlAccessType.FIELD) +public class HgPackages implements Iterable +{ + + /** + * Method description + * + * + * @return + */ + @Override + public Iterator iterator() + { + return packages.iterator(); + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + public List getPackages() + { + return packages; + } + + //~--- set methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param packages + */ + public void setPackages(List packages) + { + this.packages = packages; + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + @XmlElement(name = "package") + private List packages; +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/UnixHgInstaller.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/UnixHgInstaller.java new file mode 100644 index 0000000000..26ea293c12 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/UnixHgInstaller.java @@ -0,0 +1,152 @@ +/** + * 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.installer; + +//~--- non-JDK imports -------------------------------------------------------- + +import sonia.scm.repository.HgConfig; +import sonia.scm.util.IOUtil; +import sonia.scm.util.Util; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; +import java.io.IOException; + +import java.util.List; + +/** + * + * @author Sebastian Sdorra + */ +public class UnixHgInstaller extends AbstractHgInstaller +{ + + /** Field description */ + public static final String COMMAND_HG = "hg"; + + /** Field description */ + public static final String COMMAND_PYTHON = "python"; + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * + * @param baseDirectory + * @param config + * + * @throws IOException + */ + @Override + public void install(File baseDirectory, HgConfig config) throws IOException + { + super.install(baseDirectory, config); + + // search mercurial (hg) + + if (Util.isEmpty(config.getHgBinary())) + { + String hg = IOUtil.search(COMMAND_HG); + + if (Util.isNotEmpty(hg)) + { + config.setHgBinary(hg); + + // search python in the same folder + File hgFile = new File(hg); + + if (hgFile.exists()) + { + File pythonFile = new File(hgFile.getParentFile(), COMMAND_PYTHON); + + if (pythonFile.exists()) + { + config.setPythonBinary(pythonFile.getAbsolutePath()); + } + } + } + } + + // search python + + if (Util.isEmpty(config.getPythonBinary())) + { + config.setPythonBinary(IOUtil.search(COMMAND_PYTHON)); + } + } + + /** + * Method description + * + * + * + * @param baseDirectory + * @param config + */ + @Override + public void update(File baseDirectory, HgConfig config) + { + + // do nothing + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + @Override + public List getHgInstallations() + { + return IOUtil.searchAll(COMMAND_HG); + } + + /** + * Method description + * + * + * @return + */ + @Override + public List getPythonInstallations() + { + return IOUtil.searchAll(COMMAND_PYTHON); + } +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/WindowsHgInstaller.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/WindowsHgInstaller.java new file mode 100644 index 0000000000..879eead8ff --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/WindowsHgInstaller.java @@ -0,0 +1,428 @@ +/** + * 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.installer; + +//~--- non-JDK imports -------------------------------------------------------- + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import sonia.scm.repository.HgConfig; +import sonia.scm.util.IOUtil; +import sonia.scm.util.RegistryUtil; +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.List; + +/** + * + * @author Sebastian Sdorra + */ +public class WindowsHgInstaller extends AbstractHgInstaller +{ + + /** Field description */ + private static final String FILE_LIBRARY_ZIP = "library.zip"; + + /** Field description */ + private static final String FILE_LIB_MERCURIAL = + "Lib\\site-packages\\mercurial"; + + /** Field description */ + private static final String FILE_MERCURIAL_EXE = "hg.exe"; + + /** Field description */ + private static final String FILE_MERCURIAL_SCRIPT = "hg.bat"; + + /** Field description */ + private static final String FILE_SCRIPTS = "Scripts"; + + /** Field description */ + private static final String FILE_TEMPLATES = "templates"; + + /** Field description */ + private static final String[] REGISTRY_HG = new String[] + { + + // TortoiseHg + "HKEY_CURRENT_USER\\Software\\TortoiseHg", + + // Mercurial + "HKEY_CURRENT_USER\\Software\\Mercurial\\InstallDir" + }; + + /** Field description */ + private static final String[] REGISTRY_PYTHON = new String[] + { + + // .py files + "HKEY_CLASSES_ROOT\\Python.File\\shell\\open\\command" + }; + + /** the logger for WindowsHgInstaller */ + private static final Logger logger = + LoggerFactory.getLogger(WindowsHgInstaller.class); + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * + * @param baseDirectory + * @param config + * + * @throws IOException + */ + @Override + public void install(File baseDirectory, HgConfig config) throws IOException + { + super.install(baseDirectory, config); + + if (Util.isEmpty(config.getPythonBinary())) + { + String pythonBinary = getPythonBinary(); + + config.setPythonBinary(pythonBinary); + } + + if (Util.isEmpty(config.getHgBinary())) + { + File hgScript = getMercurialScript(config.getPythonBinary()); + + if (hgScript != null) + { + config.setHgBinary(hgScript.getAbsolutePath()); + } + } + + File hgDirectory = getMercurialDirectory(config.getHgBinary()); + + if (hgDirectory != null) + { + installHg(baseDirectory, config, hgDirectory); + } + + checkForOptimizedByteCode(config); + } + + /** + * Method description + * + * + * + * @param baseDirectory + * @param config + */ + @Override + public void update(File baseDirectory, HgConfig config) {} + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + @Override + public List getHgInstallations() + { + return getInstallations(REGISTRY_HG); + } + + /** + * Method description + * + * + * @return + */ + @Override + public List getPythonInstallations() + { + return getInstallations(REGISTRY_PYTHON); + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param config + */ + private void checkForOptimizedByteCode(HgConfig config) + { + boolean optimized = false; + String path = config.getPythonPath(); + + if (Util.isNotEmpty(path)) + { + for (String part : path.split(";")) + { + if (checkForOptimizedByteCode(part)) + { + optimized = true; + + break; + } + } + } + + config.setUseOptimizedBytecode(optimized); + } + + /** + * Method description + * + * + * @param part + * + * @return + */ + private boolean checkForOptimizedByteCode(String part) + { + File libDir = new File(part); + String[] pyoFiles = libDir.list(new FilenameFilter() + { + @Override + public boolean accept(File file, String name) + { + return name.toLowerCase().endsWith(".pyo"); + } + }); + + return Util.isNotEmpty(pyoFiles); + } + + /** + * Method description + * + * + * + * @param baseDirectory + * @param config + * @param hgDirectory + * + * @throws IOException + */ + private void installHg(File baseDirectory, HgConfig config, File hgDirectory) + throws IOException + { + if (logger.isInfoEnabled()) + { + logger.info("installing mercurial {}", hgDirectory.getAbsolutePath()); + } + + File libDir = new File(baseDirectory, "lib\\hg"); + + IOUtil.mkdirs(libDir); + + File libraryZip = new File(hgDirectory, FILE_LIBRARY_ZIP); + + if (libraryZip.exists()) + { + IOUtil.extract(libraryZip, libDir); + config.setPythonPath(libDir.getAbsolutePath()); + } + + File templateDirectory = new File(hgDirectory, FILE_TEMPLATES); + + if (templateDirectory.exists()) + { + IOUtil.copy(templateDirectory, new File(libDir, FILE_TEMPLATES)); + } + + File hg = new File( hgDirectory, FILE_MERCURIAL_EXE ); + if ( hg.exists() ) + { + config.setHgBinary(hg.getAbsolutePath()); + } + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param registryKeys + * + * @return + */ + private List getInstallations(String[] registryKeys) + { + List installations = new ArrayList(); + + for (String registryKey : registryKeys) + { + String path = RegistryUtil.getRegistryValue(registryKey); + + if (path != null) + { + File file = new File(path, FILE_MERCURIAL_EXE); + + if (file.exists()) + { + installations.add(file.getAbsolutePath()); + } + } + } + + return installations; + } + + /** + * Method description + * + * + * + * @param hgBinary + * @return + */ + private File getMercurialDirectory(String hgBinary) + { + File directory = null; + + if ( Util.isNotEmpty(hgBinary) ) + { + File hg = new File(hgBinary); + + if (hg.exists() && hg.isFile()) + { + directory = hg.getParentFile(); + } + } + + if ( directory == null ) + { + directory = getMercurialDirectoryFromRegistry(); + } + + return directory; + } + + /** + * Method description + * + * + * @return + */ + private File getMercurialDirectoryFromRegistry() + { + File directory = null; + + for (String registryKey : REGISTRY_HG) + { + String path = RegistryUtil.getRegistryValue(registryKey); + + if (path != null) + { + directory = new File(path); + + if (!directory.exists()) + { + directory = null; + } + else + { + break; + } + } + } + + return directory; + } + + /** + * Returns the location of the script to run Mercurial, if Mercurial is + * installed as a Python package from source. Only packages that include a + * templates directory will be recognized. + * + * @param pythonBinary + * + * @return + */ + private File getMercurialScript(String pythonBinary) + { + File hgScript = null; + + if (pythonBinary != null) + { + File pythonBinaryFile = new File(pythonBinary); + + if (pythonBinaryFile.exists()) + { + File pythonDir = pythonBinaryFile.getParentFile(); + File scriptsDir = new File(pythonDir, FILE_SCRIPTS); + File potentialHgScript = new File(scriptsDir, FILE_MERCURIAL_SCRIPT); + File mercurialPackageDir = new File(pythonDir, FILE_LIB_MERCURIAL); + File templatesDir = new File(mercurialPackageDir, FILE_TEMPLATES); + + if (potentialHgScript.exists() && templatesDir.exists()) + { + hgScript = potentialHgScript; + } + } + } + + return hgScript; + } + + /** + * Method description + * + * + * @return + */ + private String getPythonBinary() + { + String python = RegistryUtil.getRegistryValue(REGISTRY_PYTHON[0]); + + if (python == null) + { + python = IOUtil.search(new String[0], "python"); + } + + return python; + } +} 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 new file mode 100644 index 0000000000..eed515a139 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgChangesetParser.java @@ -0,0 +1,238 @@ +/** + * 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 new file mode 100644 index 0000000000..0404876768 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgChangesetViewer.java @@ -0,0 +1,237 @@ +/** + * 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.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import sonia.scm.io.Command; +import sonia.scm.io.CommandResult; +import sonia.scm.io.SimpleCommand; +import sonia.scm.util.IOUtil; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; + +import java.util.List; + +import javax.xml.parsers.ParserConfigurationException; + +/** + * + * @author Sebastian Sdorra + */ +public class HgChangesetViewer implements ChangesetViewer +{ + + /** Field description */ + public static final String ID_TIP = "tip"; + + /** Field description */ + //J- + public static final String TEMPLATE_CHANGESETS = + "\"" + + "{rev}:{node|short}" + + "{author|escape}" + + "{desc|escape}" + + "{date|isodatesec}" + + "{tags}" + + "{branches}" + + "{file_adds}" + + "{file_mods}" + + "{file_dels}" + + "\""; + //J+ + + /** Field description */ + public static final String TEMPLATE_TOTAL = "{rev}"; + + /** the logger for HgChangesetViewer */ + private static final Logger logger = + LoggerFactory.getLogger(HgChangesetViewer.class); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * + * @param handler + * @param repository + */ + public HgChangesetViewer(HgRepositoryHandler handler, Repository repository) + { + this.handler = handler; + this.repository = repository; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * + * + * @param start + * @param max + * + * @return + */ + @Override + public ChangesetPagingResult getChangesets(int start, int max) + { + ChangesetPagingResult changesets = null; + InputStream in = null; + + try + { + String repositoryPath = getRepositoryPath(repository); + int total = getTotalChangesets(repositoryPath); + int startRev = total - start; + int endRev = total - start - (max - 1); + + if (endRev < 0) + { + endRev = 0; + } + + Command command = new SimpleCommand(handler.getConfig().getHgBinary(), + "-R", repositoryPath, "log", "-r", + startRev + ":" + endRev, "--template", + TEMPLATE_CHANGESETS); + CommandResult result = command.execute(); + + if (result.isSuccessfull()) + { + StringBuilder sb = new StringBuilder(""); + + sb.append(result.getOutput()).append(""); + + List changesetList = new HgChangesetParser().parse( + new InputSource( + new StringReader(sb.toString()))); + + changesets = new ChangesetPagingResult(total, changesetList); + } + else if ( logger.isErrorEnabled() ) + { + logger.error( + "command for fetching changesets failed with exit code {} and output {}", + result.getReturnCode(), + result.getOutput() + ); + } + } + catch (ParserConfigurationException ex) + { + logger.error("could not parse changesets", ex); + } + catch (IOException ex) + { + logger.error("could not load changesets", ex); + } + catch (SAXException ex) + { + logger.error("could not unmarshall changesets", ex); + } + finally + { + IOUtil.close(in); + } + + return changesets; + } + + /** + * Method description + * + * + * @param repository + * + * @return + */ + private String getRepositoryPath(Repository repository) + { + return handler.getDirectory(repository).getAbsolutePath(); + } + + /** + * Method description + * + * + * @param repositoryPath + * + * @return + * + * @throws IOException + */ + private int getTotalChangesets(String repositoryPath) throws IOException + { + int total = -1; + Command command = new SimpleCommand(handler.getConfig().getHgBinary(), + "-R", repositoryPath, "tip", "--template", + TEMPLATE_TOTAL); + CommandResult result = command.execute(); + + if (result.isSuccessfull()) + { + total = Integer.parseInt(result.getOutput().trim()); + } + else if ( logger.isErrorEnabled() ) + { + logger.error( + "could not read tip revision, command returned with exit code {} and content {}", + result.getReturnCode(), + result.getOutput() + ); + } + + return total; + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private HgRepositoryHandler handler; + + /** Field description */ + private Repository repository; +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgConfig.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgConfig.java new file mode 100644 index 0000000000..a3210b4f14 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgConfig.java @@ -0,0 +1,176 @@ +/** + * 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 sonia.scm.util.Util; + +//~--- JDK imports ------------------------------------------------------------ + +import javax.xml.bind.annotation.XmlRootElement; + +/** + * + * @author Sebastian Sdorra + */ +@XmlRootElement(name = "config") +public class HgConfig extends SimpleRepositoryConfig +{ + + /** + * Constructs ... + * + */ + public HgConfig() {} + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + public String getHgBinary() + { + return hgBinary; + } + + /** + * Method description + * + * + * @return + */ + public String getPythonBinary() + { + return pythonBinary; + } + + /** + * Method description + * + * + * @return + */ + public String getPythonPath() + { + return pythonPath; + } + + /** + * Method description + * + * + * @return + */ + public boolean isUseOptimizedBytecode() + { + return useOptimizedBytecode; + } + + /** + * Method description + * + * + * @return + */ + @Override + public boolean isValid() + { + return super.isValid() && Util.isNotEmpty(hgBinary) + && Util.isNotEmpty(pythonBinary); + } + + //~--- set methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param hgBinary + */ + public void setHgBinary(String hgBinary) + { + this.hgBinary = hgBinary; + } + + /** + * Method description + * + * + * @param pythonBinary + */ + public void setPythonBinary(String pythonBinary) + { + this.pythonBinary = pythonBinary; + } + + /** + * Method description + * + * + * @param pythonPath + */ + public void setPythonPath(String pythonPath) + { + this.pythonPath = pythonPath; + } + + /** + * Method description + * + * + * @param useOptimizedBytecode + */ + public void setUseOptimizedBytecode(boolean useOptimizedBytecode) + { + this.useOptimizedBytecode = useOptimizedBytecode; + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private String hgBinary; + + /** Field description */ + private String pythonBinary; + + /** Field description */ + private String pythonPath = ""; + + /** Field description */ + private boolean useOptimizedBytecode = false; +} 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 new file mode 100644 index 0000000000..838f23c03a --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryBrowser.java @@ -0,0 +1,238 @@ +/** + * 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; + +//~--- 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; +import javax.xml.bind.JAXBException; + +/** + * + * @author Sebastian Sdorra + */ +public class HgRepositoryBrowser 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 --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param handler + * @param repository + * @param browserResultContext + */ + public HgRepositoryBrowser(HgRepositoryHandler handler, + Repository repository, + JAXBContext browserResultContext) + { + this.handler = handler; + this.repository = repository; + this.browserResultContext = browserResultContext; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param revision + * @param path + * @param output + * + * + * @throws IOException + * @throws RepositoryException + */ + @Override + public void getContent(String revision, String path, OutputStream output) + throws IOException, RepositoryException + { + if (Util.isEmpty(revision)) + { + revision = DEFAULT_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(); + InputStream input = null; + + try + { + input = p.getInputStream(); + IOUtil.copy(input, output); + } + finally + { + IOUtil.close(input); + } + } + + /** + * Method description + * + * + * @param revision + * @param path + * + * @return + * + * @throws IOException + * @throws RepositoryException + */ + @Override + public BrowserResult getResult(String revision, String path) + throws IOException, RepositoryException + { + HgConfig config = handler.getConfig(); + ProcessBuilder pb = new ProcessBuilder(config.getPythonBinary()); + Map env = pb.environment(); + + env.put(ENV_PYTHON_PATH, Util.nonNull(config.getPythonPath())); + + String directory = handler.getDirectory(repository).getAbsolutePath(); + + env.put(ENV_REPOSITORY_PATH, directory); + + if (Util.isEmpty(revision)) + { + revision = DEFAULT_REVISION; + } + + env.put(ENV_REVISION, revision); + env.put(ENV_PATH, Util.nonNull(path)); + + Process p = pb.start(); + BrowserResult result = null; + InputStream resource = null; + InputStream input = null; + OutputStream output = null; + + try + { + resource = HgRepositoryBrowser.class.getResourceAsStream(RESOURCE_BROWSE); + output = p.getOutputStream(); + IOUtil.copy(resource, output); + output.close(); + + // IOUtil.copy(p.getErrorStream(), System.err); + input = p.getInputStream(); + result = + (BrowserResult) browserResultContext.createUnmarshaller().unmarshal( + input); + + // IOUtil.copy(input, System.out); + input.close(); + } + catch (JAXBException ex) + { + logger.error("could not parse result", ex); + } + finally + { + IOUtil.close(resource); + IOUtil.close(input); + IOUtil.close(output); + } + + return result; + } + + //~--- 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 new file mode 100644 index 0000000000..15dd68db96 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java @@ -0,0 +1,290 @@ +/** + * 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 org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import sonia.scm.ConfigurationException; +import sonia.scm.Type; +import sonia.scm.installer.HgInstaller; +import sonia.scm.installer.HgInstallerFactory; +import sonia.scm.io.ExtendedCommand; +import sonia.scm.io.FileSystem; +import sonia.scm.io.INIConfiguration; +import sonia.scm.io.INIConfigurationWriter; +import sonia.scm.io.INISection; +import sonia.scm.plugin.ext.Extension; +import sonia.scm.store.StoreFactory; +import sonia.scm.util.AssertUtil; +import sonia.scm.web.HgWebConfigWriter; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; +import java.io.IOException; + + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; + +/** + * + * @author Sebastian Sdorra + */ +@Singleton +@Extension +public class HgRepositoryHandler + extends AbstractSimpleRepositoryHandler +{ + + /** Field description */ + public static final String TYPE_DISPLAYNAME = "Mercurial"; + + /** Field description */ + public static final String TYPE_NAME = "hg"; + + /** Field description */ + public static final Type TYPE = new Type(TYPE_NAME, TYPE_DISPLAYNAME); + + /** the logger for HgRepositoryHandler */ + private static final Logger logger = + LoggerFactory.getLogger(HgRepositoryHandler.class); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param storeFactory + * @param fileSystem + */ + @Inject + public HgRepositoryHandler(StoreFactory storeFactory, FileSystem fileSystem) + { + super(storeFactory, fileSystem); + + try + { + this.browserResultContext = JAXBContext.newInstance(BrowserResult.class); + } + catch (JAXBException ex) + { + throw new ConfigurationException("could not create jaxbcontext", ex); + } + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param autoConfig + */ + public void doAutoConfiguration(HgConfig autoConfig) + { + HgInstaller installer = HgInstallerFactory.createInstaller(); + + try + { + if (logger.isDebugEnabled()) + { + logger.debug("installing mercurial with {}", + installer.getClass().getName()); + } + + installer.install(baseDirectory, autoConfig); + config = autoConfig; + storeConfig(); + new HgWebConfigWriter(config).write(); + } + catch (IOException ioe) + { + if (logger.isErrorEnabled()) + { + logger.error( + "Could not write Hg CGI for inital config. " + + "HgWeb may not function until a new Hg config is set", ioe); + } + } + } + + /** + * Method description + * + */ + @Override + public void loadConfig() + { + super.loadConfig(); + + if (config == null) + { + doAutoConfiguration(new HgConfig()); + } + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param repository + * + * @return + */ + @Override + public ChangesetViewer getChangesetViewer(Repository repository) + { + HgChangesetViewer changesetViewer = null; + + AssertUtil.assertIsNotNull(repository); + + String type = repository.getType(); + + AssertUtil.assertIsNotEmpty(type); + + if (TYPE_NAME.equals(type)) + { + changesetViewer = new HgChangesetViewer(this, repository); + } + else + { + throw new IllegalArgumentException("mercurial repository is required"); + } + + return changesetViewer; + } + + /** + * Method description + * + * + * @param repository + * + * @return + */ + @Override + public RepositoryBrowser getRepositoryBrowser(Repository repository) + { + return new HgRepositoryBrowser(this, repository, browserResultContext); + } + + /** + * 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.getHgBinary(), "init", + directory.getPath()); + } + + /** + * Writes .hg/hgrc and disables hg access control + * see HgPermissionFilter + * + * @param repository + * @param directory + * + * @throws IOException + * @throws RepositoryException + */ + @Override + protected void postCreate(Repository repository, File directory) + throws IOException, RepositoryException + { + File hgrcFile = new File(directory, + ".hg".concat(File.separator).concat("hgrc")); + INIConfiguration hgrc = new INIConfiguration(); + INISection webSection = new INISection("web"); + + webSection.setParameter("push_ssl", "false"); + webSection.setParameter("allow_read", "*"); + webSection.setParameter("allow_push", "*"); + hgrc.addSection(webSection); + + INIConfigurationWriter writer = new INIConfigurationWriter(); + + writer.write(hgrc, hgrcFile); + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + @Override + protected Class getConfigClass() + { + return HgConfig.class; + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private JAXBContext browserResultContext; +} 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 new file mode 100644 index 0000000000..db3794c39f --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java @@ -0,0 +1,263 @@ +/** + * 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.config.ScmConfiguration; +import sonia.scm.repository.HgConfig; +import sonia.scm.repository.HgRepositoryHandler; +import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryManager; +import sonia.scm.util.AssertUtil; +import sonia.scm.web.cgi.CGIExecutor; +import sonia.scm.web.cgi.CGIExecutorFactory; + +//~--- 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.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * + * @author Sebastian Sdorra + */ +@Singleton +public class HgCGIServlet extends HttpServlet +{ + + /** 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 = -3492811300905099810L; + + /** Field description */ + public static final Pattern PATTERN_REPOSITORYNAME = + Pattern.compile("/[^/]+/([^/]+)(?:/.*)?"); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * + * + * + * @param cgiExecutorFactory + * @param configuration + * @param repositoryManager + * @param handler + */ + @Inject + public HgCGIServlet(CGIExecutorFactory cgiExecutorFactory, + ScmConfiguration configuration, + RepositoryManager repositoryManager, + HgRepositoryHandler handler) + { + this.cgiExecutorFactory = cgiExecutorFactory; + this.configuration = configuration; + this.repositoryManager = repositoryManager; + this.handler = handler; + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @throws ServletException + */ + @Override + public void init() throws ServletException + { + command = HgUtil.getCGI(); + super.init(); + } + + /** + * Method description + * + * + * @param request + * @param response + * + * @throws IOException + * @throws ServletException + */ + @Override + protected void service(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException + { + Repository repository = getRepository(request); + + if (repository == null) + { + throw new ServletException("repository not found"); + } + + String name = repository.getName(); + File directory = handler.getDirectory(repository); + String pythonPath = ""; + HgConfig config = handler.getConfig(); + + if (config != null) + { + pythonPath = config.getPythonPath(); + + if (pythonPath == null) + { + pythonPath = ""; + } + } + + CGIExecutor executor = cgiExecutorFactory.createExecutor(configuration, + getServletContext(), request, response); + + executor.getEnvironment().set(ENV_REPOSITORY_NAME, name); + executor.getEnvironment().set(ENV_REPOSITORY_PATH, + directory.getAbsolutePath()); + executor.getEnvironment().set(ENV_PYTHON_PATH, pythonPath); + + String interpreter = getInterpreter(); + + if (interpreter != null) + { + executor.setInterpreter(interpreter); + } + + executor.execute(command.getAbsolutePath()); + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + private String getInterpreter() + { + HgConfig config = handler.getConfig(); + + AssertUtil.assertIsNotNull(config); + + String python = config.getPythonBinary(); + + if ((python != null) && config.isUseOptimizedBytecode()) + { + python = python.concat(" -O"); + } + + return python; + } + + /** + * 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(HgRepositoryHandler.TYPE_NAME, repositoryname); + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private CGIExecutorFactory cgiExecutorFactory; + + /** Field description */ + private File command; + + /** Field description */ + private ScmConfiguration configuration; + + /** Field description */ + private HgRepositoryHandler handler; + + /** Field description */ + private RepositoryManager repositoryManager; +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java new file mode 100644 index 0000000000..c44c422ea5 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.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.HgRepositoryHandler; +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 HgPermissionFilter extends RegexPermissionFilter +{ + + /** + * Constructs ... + * + * + * @param securityContextProvider + * @param repositoryManager + */ + @Inject + public HgPermissionFilter( + Provider securityContextProvider, + RepositoryManager repositoryManager) + { + super(securityContextProvider, repositoryManager); + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + @Override + protected String getType() + { + return HgRepositoryHandler.TYPE_NAME; + } + + /** + * Method description + * + * + * @param request + * + * @return + */ + @Override + protected boolean isWriteRequest(HttpServletRequest request) + { + return !request.getMethod().equalsIgnoreCase("GET"); + } +} 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 new file mode 100644 index 0000000000..7013f8a8db --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.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 HgServletModule extends ServletModule +{ + + /** Field description */ + public static final String MAPPING_HG = "/hg/*"; + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + */ + @Override + protected void configureServlets() + { + filter(MAPPING_HG).through(BasicAuthenticationFilter.class); + filter(MAPPING_HG).through(HgPermissionFilter.class); + serve(MAPPING_HG).with(HgCGIServlet.class); + } +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgUtil.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgUtil.java new file mode 100644 index 0000000000..2148751b31 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgUtil.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 HgUtil +{ + + /** Field description */ + public static final String CGI_DIRECTORY = "cgi-bin"; + + /** Field description */ + public static final String CGI_NAME = "hgweb.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/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgWebConfigWriter.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgWebConfigWriter.java new file mode 100644 index 0000000000..6b6ff56e7a --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgWebConfigWriter.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.HgConfig; +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 HgWebConfigWriter +{ + + /** Field description */ + public static final String CGI_TEMPLATE = "/sonia/scm/hgweb.py"; + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param config + */ + public HgWebConfigWriter(HgConfig config) + { + this.config = config; + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * + * @throws IOException + */ + public void write() throws IOException + { + File cgiFile = HgUtil.getCGI(); + + writeCGIFile(cgiFile); + } + + /** + * Method description + * + * + * @param cgiFile + * + * @throws IOException + */ + private void writeCGIFile(File cgiFile) throws IOException + { + InputStream input = null; + OutputStream output = null; + + try + { + input = HgWebConfigWriter.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 HgConfig config; +} diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/META-INF/scm/plugin.xml b/scm-plugins/scm-hg-plugin/src/main/resources/META-INF/scm/plugin.xml new file mode 100644 index 0000000000..786d150f88 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/resources/META-INF/scm/plugin.xml @@ -0,0 +1,64 @@ + + + + + + + + + ${project.groupId} + ${project.artifactId} + ${project.version} + ${project.name} + ${project.description} + Sebastian Sdorra + ${project.url} + + + + 1.1 + + + + + + + + diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hg.config-wizard.js b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hg.config-wizard.js new file mode 100644 index 0000000000..6eff386b39 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hg.config-wizard.js @@ -0,0 +1,449 @@ +/* + * 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 + * + */ + +Ext.ns("Sonia.hg"); + +Sonia.hg.ConfigWizard = Ext.extend(Ext.Window,{ + + hgConfig: null, + title: 'Mercurial Configuration Wizard', + + initComponent: function(){ + + this.addEvents('finish'); + + var config = { + title: this.title, + layout: 'fit', + width: 420, + height: 140, + closable: true, + resizable: true, + plain: true, + border: false, + modal: true, + bodyCssClass: 'x-panel-mc', + items: [{ + id: 'hgConfigWizardPanel', + xtype: 'hgConfigWizardPanel', + hgConfig: this.hgConfig, + listeners: { + finish: { + fn: this.onFinish, + scope: this + } + } + }] + } + + Ext.apply(this, Ext.apply(this.initialConfig, config)); + Sonia.hg.ConfigWizard.superclass.initComponent.apply(this, arguments); + }, + + onFinish: function(config){ + this.fireEvent('finish', config); + this.close(); + } + +}); + +Sonia.hg.InstallationJsonReader = function(){ + this.RecordType = Ext.data.Record.create([{ + name: "path", + mapping: "path", + type: "string" + }]); +}; + +Ext.extend(Sonia.hg.InstallationJsonReader, Ext.data.JsonReader, { + + readRecords: function(o){ + this.jsonData = o; + + if (debug){ + console.debug('read installation data from json'); + console.debug(o); + } + + var records = []; + var paths = o.path; + for ( var i=0; i
\ + {id} (hg: {hg-version}, py: {python-version}, size: {size:fileSize})\ +
', + + // text + backText: 'Back', + nextText: 'Next', + finishText: 'Finish', + configureLocalText: 'Configure local installation', + configureRemoteText: 'Download and install', + loadingText: 'Loading ...', + hgInstallationText: 'Mercurial Installation', + pythonInstallationText: 'Python Installation', + hgPackageText: 'Mercurial Package', + errorTitleText: 'Error', + packageInstallationFailedText: 'Package installation failed', + installPackageText: 'install mercurial package {0}', + + initComponent: function(){ + this.addEvents('finish'); + + var packageStore = new Ext.data.JsonStore({ + storeId: 'pkgStore', + proxy: new Ext.data.HttpProxy({ + url: restUrl + 'config/repositories/hg/packages.json', + disableCaching: false + }), + fields: [ 'id', 'hg-version', 'python-version', 'size' ], + root: 'package', + listeners: { + load: { + fn: this.checkIfPackageAvailable, + scope: this + } + } + }); + + var hgInstallationStore = new Ext.data.Store({ + proxy: new Ext.data.HttpProxy({ + url: restUrl + 'config/repositories/hg/installations/hg.json' + }), + fields: [ 'path' ], + reader: new Sonia.hg.InstallationJsonReader(), + autoLoad: true, + autoDestroy: true + }); + + var pythonInstallationStore = new Ext.data.Store({ + proxy: new Ext.data.HttpProxy({ + url: restUrl + 'config/repositories/hg/installations/python.json' + }), + fields: [ 'path' ], + reader: new Sonia.hg.InstallationJsonReader(), + autoLoad: true, + autoDestroy: true + }); + + var config = { + layout: 'card', + activeItem: 0, + bodyStyle: 'padding: 5px', + defaults: { + bodyCssClass: 'x-panel-mc', + border: false, + labelWidth: 120, + width: 250 + }, + bbar: ['->',{ + id: 'move-prev', + text: this.backText, + handler: this.navHandler.createDelegate(this, [-1]), + disabled: true, + scope: this + },{ + id: 'move-next', + text: this.nextText, + handler: this.navHandler.createDelegate(this, [1]), + scope: this + },{ + id: 'finish', + text: this.finishText, + handler: this.applyChanges, + scope: this, + disabled: true + }], + items: [{ + id: 'cod', + items: [{ + id: 'configureOrDownload', + xtype: 'radiogroup', + name: 'configureOrDownload', + columns: 1, + items: [{ + boxLabel: this.configureLocalText, + name: 'cod', + inputValue: 'localInstall', + checked: true + },{ + id: 'remoteInstallRadio', + boxLabel: this.configureRemoteText, + name: 'cod', + inputValue: 'remoteInstall', + disabled: true + }] + }], + listeners: { + render: { + fn: function(panel){ + panel.body.mask(this.loadingText); + var store = Ext.StoreMgr.lookup('pkgStore'); + store.load.defer(100, store); + }, + scope: this + } + } + },{ + id: 'localInstall', + layout: 'form', + defaults: { + width: 250 + }, + items: [{ + id: 'mercurial', + fieldLabel: this.hgInstallationText, + name: 'mercurial', + xtype: 'combo', + readOnly: false, + triggerAction: 'all', + lazyRender: true, + mode: 'local', + editable: true, + store: hgInstallationStore, + valueField: 'path', + displayField: 'path', + allowBlank: false, + value: this.hgConfig.hgBinary + },{ + id: 'python', + fieldLabel: this.pythonInstallationText, + name: 'python', + xtype: 'combo', + readOnly: false, + triggerAction: 'all', + lazyRender: true, + mode: 'local', + editable: true, + store: pythonInstallationStore, + valueField: 'path', + displayField: 'path', + allowBlank: false, + value: this.hgConfig.pythonBinary + }] + },{ + id: 'remoteInstall', + layout: 'form', + defaults: { + width: 250 + }, + items: [{ + id: 'package', + fieldLabel: this.hgPackageText, + name: 'package', + xtype: 'combo', + readOnly: false, + triggerAction: 'all', + lazyRender: true, + mode: 'local', + editable: false, + store: packageStore, + valueField: 'id', + displayField: 'id', + allowBlank: false, + tpl: this.packageTemplate, + listeners: { + select: function(){ + Ext.getCmp('finish').setDisabled(false); + } + } + }] + }] + } + + Ext.apply(this, Ext.apply(this.initialConfig, config)); + Sonia.hg.ConfigWizardPanel.superclass.initComponent.apply(this, arguments); + }, + + checkIfPackageAvailable: function(store){ + Ext.getCmp('cod').body.unmask(); + var c = store.getTotalCount(); + if ( debug ){ + console.debug( "found " + c + " package(s)" ); + } + if ( c > 0 ){ + Ext.getCmp('remoteInstallRadio').setDisabled(false); + } + }, + + navHandler: function(direction){ + var layout = this.getLayout(); + var id = layout.activeItem.id; + + var next = -1; + + if ( id == 'cod' && direction == 1 ){ + var v = Ext.getCmp('configureOrDownload').getValue().getRawValue(); + var df = false; + if ( v == 'localInstall' ){ + next = 1; + } else if ( v == 'remoteInstall' ){ + next = 2; + df = true; + } + Ext.getCmp('move-prev').setDisabled(false); + Ext.getCmp('move-next').setDisabled(true); + Ext.getCmp('finish').setDisabled(df); + } + else if (direction == -1 && (id == 'localInstall' || id == 'remoteInstall')) { + next = 0; + Ext.getCmp('move-prev').setDisabled(true); + Ext.getCmp('move-next').setDisabled(false); + Ext.getCmp('finish').setDisabled(true); + } + + if ( next >= 0 ){ + layout.setActiveItem(next); + } + }, + + applyChanges: function(){ + var v = Ext.getCmp('configureOrDownload').getValue().getRawValue(); + if ( v == 'localInstall' ){ + this.applyLocalConfiguration(); + } else if ( v == 'remoteInstall' ){ + this.applyRemoteConfiguration(); + } + }, + + applyRemoteConfiguration: function(){ + if ( debug ){ + console.debug( "apply remote configuration" ); + } + + var pkg = Ext.getCmp('package').getValue(); + if ( debug ){ + console.debug( 'install mercurial package ' + pkg ); + } + + var lbox = Ext.MessageBox.show({ + title: this.loadingText, + msg: String.format(this.installPackageText, pkg), + width: 300, + wait: true, + animate: true, + progress: true, + closable: false + }); + + Ext.Ajax.request({ + url: restUrl + 'config/repositories/hg/packages/' + pkg + '.json', + method: 'POST', + scope: this, + timeout: 900000, // 15min + success: function(){ + if ( debug ){ + console.debug('package successfully installed'); + } + lbox.hide(); + this.fireEvent('finish'); + }, + failure: function(){ + if ( debug ){ + console.debug('package installation failed'); + } + lbox.hide(); + Ext.MessageBox.show({ + title: this.errorTitleText, + msg: this.packageInstallationFailedText, + buttons: Ext.MessageBox.OK, + icon:Ext.MessageBox.ERROR + }); + } + }); + + + }, + + applyLocalConfiguration: function(){ + if ( debug ){ + console.debug( "apply remote configuration" ); + } + var mercurial = Ext.getCmp('mercurial').getValue(); + var python = Ext.getCmp('python').getValue(); + if (debug){ + console.debug( 'configure mercurial=' + mercurial + " and python=" + python ); + } + delete this.hgConfig.pythonPath; + delete this.hgConfig.useOptimizedBytecode; + this.hgConfig.hgBinary = mercurial; + this.hgConfig.pythonBinary = python; + + if ( debug ){ + console.debug( this.hgConfig ); + } + + this.fireEvent('finish', this.hgConfig); + } + +}); + +// register xtype +Ext.reg('hgConfigWizardPanel', Sonia.hg.ConfigWizardPanel); + + +// i18n + +if ( i18n != null && i18n.country == 'de' ){ + + Ext.override(Sonia.hg.ConfigWizardPanel, { + + backText: 'Zurück', + nextText: 'Weiter', + finishText: 'Fertigstellen', + configureLocalText: 'Eine lokale Installation Konfigurieren', + configureRemoteText: 'Herunterladen und installieren', + loadingText: 'Lade ...', + hgInstallationText: 'Mercurial Installation', + pythonInstallationText: 'Python Installation', + hgPackageText: 'Mercurial Package', + errorTitleText: 'Fehler', + packageInstallationFailedText: 'Package Installation fehlgeschlagen', + installPackageText: 'Installiere Mercurial-Package {0}' + + }); + +} \ No newline at end of file diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hg.config.js b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hg.config.js new file mode 100644 index 0000000000..1c234c9091 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hg.config.js @@ -0,0 +1,211 @@ +/* + * 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 + * + */ + + +Ext.ns("Sonia.hg"); + +Sonia.hg.ConfigPanel = Ext.extend(Sonia.config.ConfigForm, { + + // labels + titleText: 'Mercurial Settings', + hgBinaryText: 'HG Binary', + pythonBinaryText: 'Python Binary', + pythonPathText: 'Python Module Search Path', + repositoryDirectoryText: 'Repository directory', + useOptimizedBytecodeText: 'Optimized Bytecode (.pyo)', + configWizardText: 'Start Configuration Wizard', + configWizardLabelText: 'Start Configuration Wizard', + + // helpText + hgBinaryHelpText: 'Location of Mercurial binary.', + pythonBinaryHelpText: 'Location of Python binary.', + pythonPathHelpText: 'Python Module Search Path (PYTHONPATH).', + repositoryDirectoryHelpText: 'Location of the Mercurial repositories.', + useOptimizedBytecodeHelpText: 'Use the Python "-O" switch.', + + initComponent: function(){ + + var config = { + title : this.titleText, + items : [{ + xtype : 'textfield', + fieldLabel : this.hgBinaryText, + name : 'hgBinary', + allowBlank : false, + helpText: this.hgBinaryHelpText + },{ + xtype : 'textfield', + fieldLabel : this.pythonBinaryText, + name : 'pythonBinary', + allowBlank : false, + helpText: this.pythonBinaryHelpText + },{ + xtype : 'textfield', + fieldLabel : this.pythonPathText, + name : 'pythonPath', + helpText: this.pythonPathHelpText + },{ + xtype: 'textfield', + name: 'repositoryDirectory', + fieldLabel: this.repositoryDirectoryText, + helpText: this.repositoryDirectoryHelpText, + allowBlank : false + },{ + xtype: 'checkbox', + name: 'useOptimizedBytecode', + fieldLabel: this.useOptimizedBytecodeText, + inputValue: 'true', + helpText: this.useOptimizedBytecodeHelpText + },{ + xtype: 'button', + text: this.configWizardText, + fieldLabel: this.configWizardLabelText, + handler: function(){ + var config = this.getForm().getValues(); + var wizard = new Sonia.hg.ConfigWizard({ + hgConfig: config + }); + wizard.on('finish', function(config){ + var self = Ext.getCmp('hgConfigForm'); + if ( config != null ){ + if (debug){ + console.debug( 'load config from wizard and submit to server' ); + } + self.loadConfig( self.el, 'config/repositories/hg/auto-configuration.json', 'POST', config ); + } else { + if (debug){ + console.debug( 'reload config' ); + } + self.onLoad(self.el); + } + }, this); + wizard.show(); + }, + scope: this + }] + } + + Ext.apply(this, Ext.apply(this.initialConfig, config)); + Sonia.hg.ConfigPanel.superclass.initComponent.apply(this, arguments); + }, + + onSubmit: function(values){ + this.el.mask(this.submitText); + Ext.Ajax.request({ + url: restUrl + 'config/repositories/hg.json', + method: 'POST', + jsonData: values, + scope: this, + disableCaching: true, + success: function(){ + this.el.unmask(); + }, + failure: function(){ + this.el.unmask(); + alert('failure'); + } + }); + }, + + onLoad: function(el){ + this.loadConfig(el, 'config/repositories/hg.json', 'GET'); + }, + + loadConfig: function(el, url, method, config){ + var tid = setTimeout( function(){ el.mask(this.loadingText); }, 100); + Ext.Ajax.request({ + url: restUrl + url, + method: method, + jsonData: config, + 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'); + } + }); + } + +}); + +Ext.reg("hgConfigPanel", Sonia.hg.ConfigPanel); + +// i18n + +if ( i18n != null && i18n.country == 'de' ){ + + Ext.override(Sonia.hg.ConfigPanel, { + + // labels + titleText: 'Mercurial Einstellungen', + hgBinaryText: 'HG Pfad', + pythonBinaryText: 'Python Pfad', + pythonPathText: 'Python Modul Suchpfad', + repositoryDirectoryText: 'Repository-Verzeichnis', + useOptimizedBytecodeText: 'Optimierter Bytecode (.pyo)', + autoConfigText: 'Einstellungen automatisch laden', + autoConfigLabelText: 'Automatische Einstellung', + configWizardText: 'Konfigurations-Assistenten starten', + configWizardLabelText: 'Konfigurations-Assistent', + + // helpText + hgBinaryHelpText: 'Pfad zum "hg" Befehl.', + pythonBinaryHelpText: 'Pfad zum "python" Befehl.', + pythonPathHelpText: 'Python Modul Suchpfad (PYTHONPATH).', + repositoryDirectoryHelpText: 'Verzeichnis der Mercurial-Repositories.', + useOptimizedBytecodeHelpText: 'Optimierten Bytecode verwenden (python -O).' + + }); + +} + +// register information panel + +initCallbacks.push(function(main){ + main.registerInfoPanel('hg', { + checkoutTemplate: 'hg clone {0}', + xtype: 'repositoryExtendedInfoPanel' + }); +}); + +// register config panel + +registerConfigPanel({ + id: 'hgConfigForm', + xtype : 'hgConfigPanel' +}); diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hgbrowse.py b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hgbrowse.py new file mode 100644 index 0000000000..c6b99ea826 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hgbrowse.py @@ -0,0 +1,82 @@ +import os + +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]) + + +from mercurial import hg, ui +import datetime, time + +def getName(path): + parts = path.split('/') + length = len(parts) + if path.endswith('/'): + length =- 1 + return parts[length - 1] + +repositoryPath = os.environ['SCM_REPOSITORY_PATH'] + +revision = os.environ['SCM_REVISION'] +path = os.environ['SCM_PATH'] +name = getName(path) +length = 0 +paths = [] +repo = hg.repository(ui.ui(), path = repositoryPath) +mf = repo[revision].manifest() + +if path is "": + length = 1 + for f in mf: + paths.append(f) +else: + length = len(path.split('/')) + 1 + for f in mf: + if f.startswith(path): + paths.append(f) + +files = [] +directories = [] + +for p in paths: + parts = p.split('/') + depth = len(parts) + if depth is length: + file = repo[revision][p] + files.append(file) + elif depth > length: + dirpath = '' + for i in range(0, length): + dirpath += parts[i] + '/' + if not dirpath in directories: + directories.append(dirpath) + +print '' +print '' +print ' ' + revision + '' +# todo print tag, and branch +print ' ' +for dir in directories: + print ' ' + print ' ' + getName(dir) + '' + print ' ' + dir + '' + print ' true' + print ' ' + +for file in files: + linkrev = repo[file.linkrev()] + time = int(linkrev.date()[0]) * 1000 + desc = linkrev.description() + print ' ' + print ' ' + getName(file.path()) + '' + print ' ' + file.path() + '' + print ' false' + print ' ' + str(file.size()) + '' + print ' ' + str(time).split('.')[0] + '' + print ' ' + desc + '' + print ' ' +print ' ' +print '' diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hgweb.py b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hgweb.py new file mode 100644 index 0000000000..9dce2b4f7b --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hgweb.py @@ -0,0 +1,16 @@ +#!/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'] + +from mercurial import demandimport; demandimport.enable() +from mercurial.hgweb import hgweb, wsgicgi +application = hgweb(repositoryPath) +wsgicgi.launch(application) 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 new file mode 100644 index 0000000000..3f265d7635 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/HgRepositoryHandlerTest.java @@ -0,0 +1,104 @@ +/** + * 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 sonia.scm.io.DefaultFileSystem; +import sonia.scm.store.StoreFactory; + +import static org.junit.Assert.*; +import static org.junit.Assume.*; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; + +/** + * + * @author Sebastian Sdorra + */ +public class HgRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase +{ + + /** + * Method description + * + * + * @param directory + */ + @Override + protected void checkDirectory(File directory) + { + File hgDirectory = new File(directory, ".hg"); + + assertTrue(hgDirectory.exists()); + assertTrue(hgDirectory.isDirectory()); + + File hgrc = new File(hgDirectory, "hgrc"); + + assertTrue(hgrc.exists()); + assertTrue(hgrc.isFile()); + assertTrue(hgrc.length() > 0); + } + + /** + * Method description + * + * + * @param factory + * @param directory + * + * @return + */ + @Override + protected RepositoryHandler createRepositoryHandler(StoreFactory factory, + File directory) + { + HgRepositoryHandler handler = new HgRepositoryHandler(factory, + new DefaultFileSystem()); + + handler.init(contextProvider); + handler.getConfig().setRepositoryDirectory(directory); + + // skip tests if hg not in path + if (! handler.isConfigured()) + { + System.out.println("WARNING could not find hg, skipping test"); + assumeTrue(false); + } + + return handler; + } +} diff --git a/scm-plugins/scm-svn-plugin/pom.xml b/scm-plugins/scm-svn-plugin/pom.xml new file mode 100644 index 0000000000..e28b691b52 --- /dev/null +++ b/scm-plugins/scm-svn-plugin/pom.xml @@ -0,0 +1,70 @@ + + + + 4.0.0 + + + scm-plugins + sonia.scm.plugins + 1.5-SNAPSHOT + + + sonia.scm.plugins + scm-svn-plugin + 1.5-SNAPSHOT + scm-svn-plugin + https://bitbucket.org/sdorra/scm-manager + Plugin for the version control system Subversion + + + + + javax.servlet + servlet-api + ${servlet.version} + provided + + + + org.tmatesoft.svnkit + svnkit-dav + ${svnkit-dav.version} + + + trilead-ssh2 + org.tmatesoft.svnkit + + + sqljet + org.tmatesoft.sqljet + + + + + + + + sonia.scm + scm-test + 1.5-SNAPSHOT + test + + + + + + 1.3.5.4 + + + + + + maven.scm-manager.org + scm-manager release repository + http://maven.scm-manager.org/nexus/content/groups/public + + + + + diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/api/rest/resources/SvnConfigResource.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/api/rest/resources/SvnConfigResource.java new file mode 100644 index 0000000000..cf824bcb46 --- /dev/null +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/api/rest/resources/SvnConfigResource.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.api.rest.resources; + +//~--- non-JDK imports -------------------------------------------------------- + +import com.google.inject.Inject; +import com.google.inject.Singleton; + +import sonia.scm.repository.RepositoryManager; +import sonia.scm.repository.SvnConfig; +import sonia.scm.repository.SvnRepositoryHandler; + +//~--- JDK imports ------------------------------------------------------------ + +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/svn") +@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) +public class SvnConfigResource +{ + + /** + * Constructs ... + * + * + * @param repositoryManager + */ + @Inject + public SvnConfigResource(RepositoryManager repositoryManager) + { + repositoryHandler = (SvnRepositoryHandler) repositoryManager.getHandler( + SvnRepositoryHandler.TYPE_NAME); + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + @GET + public SvnConfig getConfig() + { + SvnConfig config = repositoryHandler.getConfig(); + + if (config == null) + { + config = new SvnConfig(); + repositoryHandler.setConfig(config); + } + + return config; + } + + //~--- set methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param uriInfo + * @param config + * + * @return + */ + @POST + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public Response setConfig(@Context UriInfo uriInfo, SvnConfig config) + { + repositoryHandler.setConfig(config); + repositoryHandler.storeConfig(); + + return Response.created(uriInfo.getRequestUri()).build(); + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private SvnRepositoryHandler repositoryHandler; +} diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/Compatibility.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/Compatibility.java new file mode 100644 index 0000000000..3ff8438725 --- /dev/null +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/Compatibility.java @@ -0,0 +1,105 @@ +/** + * 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; + +/** + * + * @author Sebastian Sdorra + */ +public enum Compatibility +{ + NONE(false, false, false), PRE14(true, true, true), PRE15(false, true, true), + PRE16(false, false, true); + + /** + * Field description + * + * @param pre14Compatible + * @param pre15Compatible + * @param pre16Compatible + */ + private Compatibility(boolean pre14Compatible, boolean pre15Compatible, + boolean pre16Compatible) + { + this.pre14Compatible = pre14Compatible; + this.pre15Compatible = pre15Compatible; + this.pre16Compatible = pre16Compatible; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + public boolean isPre14Compatible() + { + return pre14Compatible; + } + + /** + * Method description + * + * + * @return + */ + public boolean isPre15Compatible() + { + return pre15Compatible; + } + + /** + * Method description + * + * + * @return + */ + public boolean isPre16Compatible() + { + return pre16Compatible; + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private boolean pre14Compatible; + + /** Field description */ + private boolean pre15Compatible; + + /** Field description */ + private boolean pre16Compatible; +} diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnChangesetViewer.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnChangesetViewer.java new file mode 100644 index 0000000000..b68c2260b6 --- /dev/null +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnChangesetViewer.java @@ -0,0 +1,207 @@ +/** + * 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.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNLogEntry; +import org.tmatesoft.svn.core.SVNLogEntryPath; +import org.tmatesoft.svn.core.SVNURL; +import org.tmatesoft.svn.core.io.SVNRepository; +import org.tmatesoft.svn.core.io.SVNRepositoryFactory; + +import sonia.scm.util.Util; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * + * @author Sebastian Sdorra + */ +public class SvnChangesetViewer implements ChangesetViewer +{ + + /** the logger for SvnChangesetViewer */ + private static final Logger logger = + LoggerFactory.getLogger(SvnChangesetViewer.class); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param handler + * @param repostory + */ + public SvnChangesetViewer(SvnRepositoryHandler handler, Repository repostory) + { + this.handler = handler; + this.repostory = repostory; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param start + * @param max + * + * @return + */ + @Override + public ChangesetPagingResult getChangesets(int start, int max) + { + ChangesetPagingResult changesets = null; + File directory = handler.getDirectory(repostory); + SVNRepository repository = null; + + try + { + repository = SVNRepositoryFactory.create(SVNURL.fromFile(directory)); + + long total = repository.getLatestRevision(); + long startRev = total - start; + long endRev = total - start - (max - 1); + + if (endRev < 0) + { + endRev = 0; + } + + List changesetList = new ArrayList(); + Collection entries = repository.log(new String[] { "" }, + null, startRev, endRev, true, true); + + for (SVNLogEntry entry : entries) + { + changesetList.add(createChangeset(entry)); + } + + changesets = new ChangesetPagingResult((int) total, changesetList); + } + catch (SVNException ex) + { + logger.error("could not open repository", ex); + } + finally + { + repository.closeSession(); + } + + return changesets; + } + + //~--- methods -------------------------------------------------------------- + + /** + * TODO: type replaced + * + * + * @param modifications + * @param entry + */ + private void appendModification(Modifications modifications, + SVNLogEntryPath entry) + { + switch (entry.getType()) + { + case SVNLogEntryPath.TYPE_ADDED : + modifications.getAdded().add(entry.getPath()); + + break; + + case SVNLogEntryPath.TYPE_DELETED : + modifications.getRemoved().add(entry.getPath()); + + break; + + case SVNLogEntryPath.TYPE_MODIFIED : + modifications.getModified().add(entry.getPath()); + + break; + } + } + + /** + * Method description + * + * + * @param entry + * + * @return + */ + @SuppressWarnings("unchecked") + private Changeset createChangeset(SVNLogEntry entry) + { + Changeset changeset = new Changeset(String.valueOf(entry.getRevision()), + entry.getDate().getTime(), + Person.toPerson(entry.getAuthor()), + entry.getMessage()); + Map changeMap = entry.getChangedPaths(); + + if (Util.isNotEmpty(changeMap)) + { + Modifications modifications = changeset.getModifications(); + + for (SVNLogEntryPath e : changeMap.values()) + { + appendModification(modifications, e); + } + } + + return changeset; + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private SvnRepositoryHandler handler; + + /** Field description */ + private Repository repostory; +} diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnConfig.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnConfig.java new file mode 100644 index 0000000000..c8d65deed5 --- /dev/null +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnConfig.java @@ -0,0 +1,81 @@ +/** + * 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 SvnConfig extends SimpleRepositoryConfig +{ + + /** + * Method description + * + * + * @return + */ + public Compatibility getCompatibility() + { + if (compatibility == null) + { + compatibility = Compatibility.NONE; + } + + return compatibility; + } + + //~--- set methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param compatibility + */ + public void setCompatibility(Compatibility compatibility) + { + this.compatibility = compatibility; + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private Compatibility compatibility = Compatibility.NONE; +} diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnRepositoryBrowser.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnRepositoryBrowser.java new file mode 100644 index 0000000000..d3c4dc02e1 --- /dev/null +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnRepositoryBrowser.java @@ -0,0 +1,290 @@ +/** + * 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.tmatesoft.svn.core.SVNDirEntry; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNNodeKind; +import org.tmatesoft.svn.core.SVNProperties; +import org.tmatesoft.svn.core.SVNURL; +import org.tmatesoft.svn.core.io.SVNRepository; +import org.tmatesoft.svn.core.io.SVNRepositoryFactory; + +import sonia.scm.util.Util; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * + * @author Sebastian Sdorra + */ +public class SvnRepositoryBrowser implements RepositoryBrowser +{ + + /** the logger for SvnRepositoryBrowser */ + private static final Logger logger = + LoggerFactory.getLogger(SvnRepositoryBrowser.class); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param handler + * @param repository + */ + public SvnRepositoryBrowser(SvnRepositoryHandler handler, + Repository repository) + { + this.handler = handler; + this.repository = repository; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * http://wiki.svnkit.com/Printing_Out_File_Contents + * + * + * @param revision + * @param path + * @param output + * + * + * @throws IOException + * @throws RepositoryException + */ + @Override + public void getContent(String revision, String path, OutputStream output) + throws IOException, RepositoryException + { + long revisionNumber = getRevisionNumber(revision); + SVNRepository svnRepository = null; + + try + { + svnRepository = getSvnRepository(); + svnRepository.getFile(path, revisionNumber, new SVNProperties(), output); + } + catch (SVNException ex) + { + logger.error("could not open repository", ex); + } + finally + { + close(svnRepository); + } + } + + /** + * Method description + * + * + * @param revision + * @param path + * + * @return + * + * @throws IOException + * @throws RepositoryException + */ + @Override + public BrowserResult getResult(String revision, String path) + throws IOException, RepositoryException + { + long revisionNumber = getRevisionNumber(revision); + + if (logger.isDebugEnabled()) + { + logger.debug("browser repository {} in path {} at revision {}", + new Object[] { repository.getName(), + path, revision }); + } + + BrowserResult result = null; + SVNRepository svnRepository = null; + + try + { + svnRepository = getSvnRepository(); + + Collection entries = + svnRepository.getDir(Util.nonNull(path), revisionNumber, null, + (Collection) null); + List children = new ArrayList(); + String basePath = Util.EMPTY_STRING; + + if (Util.isNotEmpty(path)) + { + basePath = path; + + if (!basePath.endsWith("/")) + { + basePath = basePath.concat("/"); + } + } + + for (SVNDirEntry entry : entries) + { + children.add(createFileObject(entry, basePath)); + } + + result = new BrowserResult(); + result.setRevision(revision); + result.setFiles(children); + } + catch (SVNException ex) + { + logger.error("could not open repository", ex); + } + finally + { + close(svnRepository); + } + + return result; + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param svnRepository + */ + private void close(SVNRepository svnRepository) + { + if (svnRepository != null) + { + svnRepository.closeSession(); + } + } + + /** + * Method description + * + * + * @param entry + * @param path + * + * @return + */ + private FileObject createFileObject(SVNDirEntry entry, String path) + { + FileObject fileObject = new FileObject(); + + fileObject.setName(entry.getName()); + fileObject.setPath(path.concat(entry.getRelativePath())); + fileObject.setDirectory(entry.getKind() == SVNNodeKind.DIR); + + if (entry.getDate() != null) + { + fileObject.setLastModified(entry.getDate().getTime()); + } + + fileObject.setLength(entry.getSize()); + fileObject.setDescription(entry.getCommitMessage()); + + return fileObject; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param revision + * + * @return + * + * @throws RepositoryException + */ + private long getRevisionNumber(String revision) throws RepositoryException + { + long revisionNumber = -1; + + if (Util.isNotEmpty(revision)) + { + try + { + revisionNumber = Long.parseLong(revision); + } + catch (NumberFormatException ex) + { + throw new RepositoryException("given revision is not a svnrevision"); + } + } + + return revisionNumber; + } + + /** + * Method description + * + * + * @return + * + * @throws SVNException + */ + private SVNRepository getSvnRepository() throws SVNException + { + File directory = handler.getDirectory(repository); + + return SVNRepositoryFactory.create(SVNURL.fromFile(directory)); + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private SvnRepositoryHandler handler; + + /** Field description */ + private Repository repository; +} diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnRepositoryHandler.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnRepositoryHandler.java new file mode 100644 index 0000000000..2cccb9347b --- /dev/null +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnRepositoryHandler.java @@ -0,0 +1,227 @@ +/** + * 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 org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory; +import org.tmatesoft.svn.core.io.SVNRepositoryFactory; + +import sonia.scm.Type; +import sonia.scm.io.FileSystem; +import sonia.scm.plugin.ext.Extension; +import sonia.scm.store.StoreFactory; +import sonia.scm.util.AssertUtil; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; +import java.io.IOException; + +/** + * + * @author Sebastian Sdorra + */ +@Singleton +@Extension +public class SvnRepositoryHandler + extends AbstractSimpleRepositoryHandler +{ + + /** Field description */ + public static final String TYPE_DISPLAYNAME = "Subversion"; + + /** Field description */ + public static final String TYPE_NAME = "svn"; + + /** Field description */ + public static final Type TYPE = new Type(TYPE_NAME, TYPE_DISPLAYNAME); + + /** the logger for SvnRepositoryHandler */ + private static final Logger logger = + LoggerFactory.getLogger(SvnRepositoryHandler.class); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param storeFactory + * @param fileSystem + */ + @Inject + public SvnRepositoryHandler(StoreFactory storeFactory, FileSystem fileSystem) + { + super(storeFactory, fileSystem); + + // setup FSRepositoryFactory for SvnRepositoryBrowser + FSRepositoryFactory.setup(); + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param repository + * + * @return + */ + @Override + public ChangesetViewer getChangesetViewer(Repository repository) + { + SvnChangesetViewer changesetViewer = null; + + AssertUtil.assertIsNotNull(repository); + + String type = repository.getType(); + + AssertUtil.assertIsNotEmpty(type); + + if (TYPE_NAME.equals(type)) + { + changesetViewer = new SvnChangesetViewer(this, repository); + } + else + { + throw new IllegalArgumentException("mercurial repository is required"); + } + + return changesetViewer; + } + + /** + * Method description + * + * + * @param repository + * + * @return + */ + @Override + public RepositoryBrowser getRepositoryBrowser(Repository repository) + { + AssertUtil.assertIsNotNull(repository); + + return new SvnRepositoryBrowser(this, repository); + } + + /** + * Method description + * + * + * @return + */ + @Override + public Type getType() + { + return TYPE; + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param repository + * @param directory + * + * @throws IOException + * @throws RepositoryException + */ + @Override + protected void create(Repository repository, File directory) + throws RepositoryException, IOException + { + Compatibility comp = config.getCompatibility(); + + if (logger.isDebugEnabled()) + { + StringBuilder log = new StringBuilder("create svn repository \""); + + log.append(directory.getName()).append("\": pre14Compatible="); + log.append(comp.isPre14Compatible()).append(", pre15Compatible="); + log.append(comp.isPre15Compatible()).append(", pre16Compatible="); + log.append(comp.isPre16Compatible()); + logger.debug(log.toString()); + } + + try + { + SVNRepositoryFactory.createLocalRepository(directory, null, true, false, + comp.isPre14Compatible(), comp.isPre15Compatible(), + comp.isPre16Compatible()); + } + catch (SVNException ex) + { + throw new RepositoryException(ex); + } + } + + /** + * Method description + * + * + * @return + */ + @Override + protected SvnConfig createInitialConfig() + { + return new SvnConfig(); + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + @Override + protected Class getConfigClass() + { + return SvnConfig.class; + } +} diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVConfig.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVConfig.java new file mode 100644 index 0000000000..0a39e80561 --- /dev/null +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVConfig.java @@ -0,0 +1,240 @@ +/** + * 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.tmatesoft.svn.core.internal.server.dav.DAVConfig; +import org.tmatesoft.svn.core.internal.server.dav.SVNPathBasedAccess; + +import sonia.scm.repository.SvnConfig; + +/** + * + * @author Sebastian Sdorra + */ +public class SvnDAVConfig extends DAVConfig +{ + + /** + * Constructs ... + * + * + * @param davConfig + * @param config + */ + public SvnDAVConfig(DAVConfig davConfig, SvnConfig config) + { + this.davConfig = davConfig; + this.config = config; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + @Override + public String getActivitiesDBPath() + { + return davConfig.getActivitiesDBPath(); + } + + /** + * Method description + * + * + * @return + */ + @Override + public String getRepositoryName() + { + return davConfig.getRepositoryName(); + } + + /** + * Method description + * + * + * @return + */ + @Override + public String getRepositoryParentPath() + { + return config.getRepositoryDirectory().getAbsolutePath(); + } + + /** + * Method description + * + * + * @return + */ + @Override + public String getRepositoryPath() + { + return davConfig.getRepositoryPath(); + } + + /** + * Method description + * + * + * @return + */ + @Override + public SVNPathBasedAccess getSVNAccess() + { + return davConfig.getSVNAccess(); + } + + /** + * Method description + * + * + * @return + */ + @Override + public String getXSLTIndex() + { + return davConfig.getXSLTIndex(); + } + + /** + * Method description + * + * + * @return + */ + @Override + public boolean isAllowBulkUpdates() + { + return davConfig.isAllowBulkUpdates(); + } + + /** + * Method description + * + * + * @return + */ + @Override + public boolean isAllowDepthInfinity() + { + return davConfig.isAllowDepthInfinity(); + } + + /** + * Method description + * + * + * @return + */ + @Override + public boolean isAnonymousAllowed() + { + return davConfig.isAnonymousAllowed(); + } + + /** + * Method description + * + * + * @return + */ + @Override + public boolean isAutoVersioning() + { + return davConfig.isAutoVersioning(); + } + + /** + * Method description + * + * + * @return + */ + @Override + public boolean isListParentPath() + { + return davConfig.isListParentPath(); + } + + /** + * Method description + * + * + * @return + */ + @Override + public boolean isNoAuthIfAnonymousAllowed() + { + return davConfig.isNoAuthIfAnonymousAllowed(); + } + + /** + * Method description + * + * + * @return + */ + @Override + public boolean isUsingPBA() + { + return davConfig.isUsingPBA(); + } + + /** + * Method description + * + * + * @return + */ + @Override + public boolean isUsingRepositoryPathDirective() + { + return davConfig.isUsingRepositoryPathDirective(); + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private SvnConfig config; + + /** Field description */ + private DAVConfig davConfig; +} diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java new file mode 100644 index 0000000000..c5e5f6c6ab --- /dev/null +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java @@ -0,0 +1,89 @@ +/** + * 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.tmatesoft.svn.core.internal.server.dav.DAVConfig; +import org.tmatesoft.svn.core.internal.server.dav.DAVServlet; + +import sonia.scm.repository.SvnRepositoryHandler; + +/** + * + * @author Sebastian Sdorra + */ +@Singleton +public class SvnDAVServlet extends DAVServlet +{ + + /** Field description */ + private static final long serialVersionUID = -1462257085465785945L; + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param handler + */ + @Inject + public SvnDAVServlet(SvnRepositoryHandler handler) + { + this.handler = handler; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + @Override + protected DAVConfig getDAVConfig() + { + return new SvnDAVConfig(super.getDAVConfig(), handler.getConfig()); + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private SvnRepositoryHandler handler; +} diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java new file mode 100644 index 0000000000..9c7d582bd9 --- /dev/null +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java @@ -0,0 +1,114 @@ +/** + * 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.RepositoryManager; +import sonia.scm.repository.SvnRepositoryHandler; +import sonia.scm.web.filter.RegexPermissionFilter; +import sonia.scm.web.security.WebSecurityContext; + +//~--- JDK imports ------------------------------------------------------------ + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import javax.servlet.http.HttpServletRequest; + +/** + * + * @author Sebastian Sdorra + */ +@Singleton +public class SvnPermissionFilter extends RegexPermissionFilter +{ + + /** Field description */ + private static Set WRITEMETHOD_SET = + new HashSet(Arrays.asList("MKACTIVITY", "PROPPATCH", "PUT", + "CHECKOUT", "MKCOL", "MOVE", "COPY", "DELETE", "LOCK", "UNLOCK", + "MERGE")); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * + * @param securityContextProvider + * @param repositoryManager + */ + @Inject + public SvnPermissionFilter( + Provider securityContextProvider, + RepositoryManager repositoryManager) + { + super(securityContextProvider, repositoryManager); + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + @Override + protected String getType() + { + return SvnRepositoryHandler.TYPE_NAME; + } + + /** + * Method description + * + * + * @param request + * + * @return + */ + @Override + protected boolean isWriteRequest(HttpServletRequest request) + { + return WRITEMETHOD_SET.contains(request.getMethod().toUpperCase()); + } +} diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java new file mode 100644 index 0000000000..c0a30ff6c3 --- /dev/null +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java @@ -0,0 +1,80 @@ +/** + * 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.web.filter.BasicAuthenticationFilter; + +//~--- JDK imports ------------------------------------------------------------ + +import java.util.HashMap; +import java.util.Map; +import sonia.scm.plugin.ext.Extension; + +/** + * + * @author Sebastian Sdorra + */ +@Extension +public class SvnServletModule extends ServletModule +{ + + /** Field description */ + public static final String PARAMETER_SVN_PARENTPATH = "SVNParentPath"; + + /** Field description */ + public static final String PATTERN_SVN = "/svn/*"; + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + */ + @Override + protected void configureServlets() + { + filter(PATTERN_SVN).through(BasicAuthenticationFilter.class); + filter(PATTERN_SVN).through(SvnPermissionFilter.class); + + Map parameters = new HashMap(); + + parameters.put(PARAMETER_SVN_PARENTPATH, + System.getProperty("java.io.tmpdir")); + serve(PATTERN_SVN).with(SvnDAVServlet.class, parameters); + } +} diff --git a/scm-plugins/scm-svn-plugin/src/main/resources/META-INF/scm/plugin.xml b/scm-plugins/scm-svn-plugin/src/main/resources/META-INF/scm/plugin.xml new file mode 100644 index 0000000000..165fdb57cf --- /dev/null +++ b/scm-plugins/scm-svn-plugin/src/main/resources/META-INF/scm/plugin.xml @@ -0,0 +1,63 @@ + + + + + + + + + ${project.groupId} + ${project.artifactId} + ${project.version} + ${project.name} + ${project.description} + Sebastian Sdorra + ${project.url} + + + + 1.1 + + + + + + + \ No newline at end of file diff --git a/scm-plugins/scm-svn-plugin/src/main/resources/sonia/scm/svn.config.js b/scm-plugins/scm-svn-plugin/src/main/resources/sonia/scm/svn.config.js new file mode 100644 index 0000000000..a89beca241 --- /dev/null +++ b/scm-plugins/scm-svn-plugin/src/main/resources/sonia/scm/svn.config.js @@ -0,0 +1,124 @@ +/* + * 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 + * + */ + +Ext.ns("Sonia.svn"); + +Sonia.svn.ConfigPanel = Ext.extend(Sonia.config.SimpleConfigForm, { + + // labels + titleText: 'Subversion Settings', + repositoryDirectoryText: 'Repository directory', + noneCompatibility: 'No compatibility modus', + pre14CompatibleText: 'Pre 1.4 Compatible', + pre15CompatibleText: 'Pre 1.5 Compatible', + pre16CompatibleText: 'Pre 1.6 Compatible', + + // helpTexts + repositoryDirectoryHelpText: 'Location of the Suberversion repositories.', + + initComponent: function(){ + + var config = { + title : this.titleText, + configUrl: restUrl + 'config/repositories/svn.json', + items : [{ + xtype: 'textfield', + name: 'repositoryDirectory', + fieldLabel: this.repositoryDirectoryText, + helpText: this.repositoryDirectoryHelpText, + allowBlank : false + },{ + xtype: 'radiogroup', + name: 'compatibility', + columns: 1, + items: [{ + boxLabel: this.noneCompatibility, + inputValue: 'NONE', + name: 'compatibility' + },{ + boxLabel: this.pre14CompatibleText, + inputValue: 'PRE14', + name: 'compatibility' + },{ + boxLabel: this.pre15CompatibleText, + inputValue: 'PRE15', + name: 'compatibility' + },{ + boxLabel: this.pre16CompatibleText, + inputValue: 'PRE16', + name: 'compatibility' + }] + }] + } + + Ext.apply(this, Ext.apply(this.initialConfig, config)); + Sonia.svn.ConfigPanel.superclass.initComponent.apply(this, arguments); + } + +}); + +Ext.reg("svnConfigPanel", Sonia.svn.ConfigPanel); + +// i18n + +if ( i18n != null && i18n.country == 'de' ){ + + Ext.override(Sonia.svn.ConfigPanel, { + + // labels + titleText: 'Subversion Einstellungen', + repositoryDirectoryText: 'Repository-Verzeichnis', + noneCompatibility: 'Kein Kompatiblitätsmodus', + pre14CompatibleText: 'Mit Versionen vor 1.4 kompatibel', + pre15CompatibleText: 'Mit Versionen vor 1.5 kompatibel', + pre16CompatibleText: 'Mit Versionen vor 1.6 kompatibel', + + // helpTexts + repositoryDirectoryHelpText: 'Verzeichnis der Subversion-Repositories.' + + }); + +} + +// register information panel + +initCallbacks.push(function(main){ + main.registerInfoPanel('svn', { + checkoutTemplate: 'svn checkout {0}', + xtype: 'repositoryExtendedInfoPanel' + }); +}); + +// register panel + +registerConfigPanel({ + xtype : 'svnConfigPanel' +}); diff --git a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/SvnRepositoryHandlerTest.java b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/SvnRepositoryHandlerTest.java new file mode 100644 index 0000000000..ab26da171f --- /dev/null +++ b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/SvnRepositoryHandlerTest.java @@ -0,0 +1,99 @@ +/** + * 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 sonia.scm.io.DefaultFileSystem; +import sonia.scm.store.StoreFactory; + +import static org.junit.Assert.*; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; + +/** + * + * @author Sebastian Sdorra + */ +public class SvnRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase +{ + + /** + * Method description + * + * + * @param directory + */ + @Override + protected void checkDirectory(File directory) + { + File format = new File(directory, "format"); + + assertTrue(format.exists()); + assertTrue(format.isFile()); + + File db = new File(directory, "db"); + + assertTrue(db.exists()); + assertTrue(db.isDirectory()); + } + + /** + * Method description + * + * + * @param factory + * @param directory + * + * @return + */ + @Override + protected RepositoryHandler createRepositoryHandler(StoreFactory factory, + File directory) + { + SvnRepositoryHandler handler = new SvnRepositoryHandler(factory, + new DefaultFileSystem()); + + handler.init(contextProvider); + + SvnConfig config = new SvnConfig(); + + config.setRepositoryDirectory(directory); + handler.setConfig(config); + + return handler; + } +}