From 8dc56330c2a862a83ee47fc4919f753b09c11803 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Wed, 14 Sep 2011 11:13:14 +0200 Subject: [PATCH] apply patch for blame support from naver.com --- .../repository/AbstractRepositoryHandler.java | 14 + .../java/sonia/scm/repository/BlameLine.java | 206 +++++++++++++ .../scm/repository/BlamePagingResult.java | 134 ++++++++ .../sonia/scm/repository/BlameViewer.java | 56 ++++ .../sonia/scm/repository/BlameViewerUtil.java | 285 ++++++++++++++++++ .../scm/repository/RepositoryHandler.java | 13 + .../scm/repository/RepositoryManager.java | 13 + .../sonia/scm/repository/GitBlameViewer.java | 156 ++++++++++ .../scm/repository/GitRepositoryHandler.java | 31 ++ .../scm/repository/HgRepositoryHandler.java | 14 + .../sonia/scm/repository/SvnBlameViewer.java | 161 ++++++++++ .../scm/repository/SvnRepositoryHandler.java | 24 +- .../rest/resources/RepositoryResource.java | 43 ++- .../repository/xml/XmlRepositoryManager.java | 12 +- 14 files changed, 1158 insertions(+), 4 deletions(-) create mode 100644 scm-core/src/main/java/sonia/scm/repository/BlameLine.java create mode 100644 scm-core/src/main/java/sonia/scm/repository/BlamePagingResult.java create mode 100644 scm-core/src/main/java/sonia/scm/repository/BlameViewer.java create mode 100644 scm-core/src/main/java/sonia/scm/repository/BlameViewerUtil.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitBlameViewer.java create mode 100644 scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnBlameViewer.java diff --git a/scm-core/src/main/java/sonia/scm/repository/AbstractRepositoryHandler.java b/scm-core/src/main/java/sonia/scm/repository/AbstractRepositoryHandler.java index b7b8282755..cbc64b3f97 100644 --- a/scm-core/src/main/java/sonia/scm/repository/AbstractRepositoryHandler.java +++ b/scm-core/src/main/java/sonia/scm/repository/AbstractRepositoryHandler.java @@ -186,6 +186,20 @@ public abstract class AbstractRepositoryHandler blameLines) + { + this.total = total; + this.blameLines = blameLines; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + public List getBlameLines() + { + return blameLines; + } + + /** + * Method description + * + * + * @return + */ + public int getTotal() + { + return total; + } + + //~--- set methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param blameLines + */ + public void setBlameLines(List blameLines) + { + this.blameLines = blameLines; + } + + /** + * Method description + * + * + * @param total + */ + public void setTotal(int total) + { + this.total = total; + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + @XmlElement(name = "blameline") + @XmlElementWrapper(name = "blamelines") + private List blameLines; + + /** Field description */ + private int total; +} diff --git a/scm-core/src/main/java/sonia/scm/repository/BlameViewer.java b/scm-core/src/main/java/sonia/scm/repository/BlameViewer.java new file mode 100644 index 0000000000..54deb7261b --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/BlameViewer.java @@ -0,0 +1,56 @@ +/** + * 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; + +/** + * Interface description + * + * + * @version Enter version here..., 11/09/14 + * @author Enter your name here... + */ +public interface BlameViewer +{ + + /** + * Method description + * + * + * @param revision + * @param path + * + * @return + */ + public BlamePagingResult getBlame(String revision, String path); +} diff --git a/scm-core/src/main/java/sonia/scm/repository/BlameViewerUtil.java b/scm-core/src/main/java/sonia/scm/repository/BlameViewerUtil.java new file mode 100644 index 0000000000..1bbd12786c --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/BlameViewerUtil.java @@ -0,0 +1,285 @@ +/** + * 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.NotSupportedFeatuerException; +import sonia.scm.cache.Cache; +import sonia.scm.cache.CacheManager; +import sonia.scm.util.AssertUtil; + +/** + * Class description + * + * + * @version Enter version here..., 11/09/14 + * @author Enter your name here... + */ +@Singleton +public class BlameViewerUtil extends CacheClearHook +{ + + /** Field description */ + public static final String CACHE_NAME = "sonia.cache.repository.blame"; + + /** the logger for BlameViewerUtil */ + private static final Logger logger = + LoggerFactory.getLogger(BlameViewerUtil.class); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param repositoryManager + * @param cacheManager + * @return + */ + @Inject + public BlameViewerUtil(RepositoryManager repositoryManager, + CacheManager cacheManager) + { + this.repositoryManager = repositoryManager; + this.cache = cacheManager.getCache(BlameViewerCacheKey.class, + BlamePagingResult.class, CACHE_NAME); + init(repositoryManager, cache); + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param repositoryId + * @param revision + * @param path + * + * @return + * + * @throws NotSupportedFeatuerException + * @throws RepositoryException + */ + public BlamePagingResult getBlame(String repositoryId, String revision, + String path) + throws RepositoryException, NotSupportedFeatuerException + { + AssertUtil.assertIsNotEmpty(repositoryId); + + Repository repository = repositoryManager.get(repositoryId); + + if (repository == null) + { + throw new RepositoryNotFoundException( + "could not find repository with id ".concat(repositoryId)); + } + + return getBlame(repository, revision, path); + } + + /** + * Method description + * + * + * @param repository + * @param revision + * @param path + * + * @return + * + * @throws NotSupportedFeatuerException + * @throws RepositoryException + */ + public BlamePagingResult getBlame(Repository repository, String revision, + String path) + throws RepositoryException, NotSupportedFeatuerException + { + AssertUtil.assertIsNotNull(repository); + + BlameViewer viewer = repositoryManager.getBlameViewer(repository); + + if (viewer == null) + { + throw new NotSupportedFeatuerException( + "BlameViewer is not supported for type ".concat( + repository.getType())); + } + + BlameViewerCacheKey key = new BlameViewerCacheKey(repository.getId(), + revision, path); + BlamePagingResult result = cache.get(key); + + if (result == null) + { + result = viewer.getBlame(revision, path); + cache.put(key, result); + } + else if (logger.isDebugEnabled()) + { + logger.debug("fetch blameviewer results from cache"); + } + + return result; + } + + //~--- inner classes -------------------------------------------------------- + + /** + * Class description + * + * + * @version Enter version here... + * @author Enter your name here... + */ + private static class BlameViewerCacheKey + { + + /** + * Constructs ... + * + * + * @param repositoryId + * @param revision + * @param path + */ + public BlameViewerCacheKey(String repositoryId, String revision, + String path) + { + this.repositoryId = repositoryId; + this.revision = revision; + this.path = path; + } + + //~--- methods ------------------------------------------------------------ + + /** + * Method description + * + * + * @param obj + * + * @return + */ + @Override + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + + if (getClass() != obj.getClass()) + { + return false; + } + + final BlameViewerCacheKey other = (BlameViewerCacheKey) obj; + + if ((this.repositoryId == null) + ? (other.repositoryId != null) + : !this.repositoryId.equals(other.repositoryId)) + { + return false; + } + + if ((this.revision == null) + ? (other.revision != null) + : !this.revision.equals(other.revision)) + { + return false; + } + + if ((this.path == null) + ? (other.path != null) + : !this.path.equals(other.path)) + { + return false; + } + + return true; + } + + /** + * Method description + * + * + * @return + */ + @Override + public int hashCode() + { + int hash = 3; + + hash = 53 * hash + ((this.repositoryId != null) + ? this.repositoryId.hashCode() + : 0); + hash = 53 * hash + ((this.revision != null) + ? this.revision.hashCode() + : 0); + hash = 53 * hash + ((this.path != null) + ? this.path.hashCode() + : 0); + + return hash; + } + + //~--- fields ------------------------------------------------------------- + + /** Field description */ + private String path; + + /** Field description */ + private String repositoryId; + + /** Field description */ + private String revision; + } + + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private Cache cache; + + /** Field description */ + private RepositoryManager repositoryManager; +} diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryHandler.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryHandler.java index c9142d3b7e..69cc7db03e 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryHandler.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryHandler.java @@ -63,6 +63,19 @@ public interface RepositoryHandler //~--- get methods ---------------------------------------------------------- + /** + * Method description + * + * + * @param repository + * + * @return + * + * @throws RepositoryException + */ + public BlameViewer getBlameViewer(Repository repository) + throws RepositoryException; + /** * Method description * diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryManager.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryManager.java index d373acd13c..0d5028a523 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryManager.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryManager.java @@ -64,6 +64,19 @@ public interface RepositoryManager */ public Repository get(String type, String name); + /** + * Method description + * + * + * + * @param repository + * @return null if BlameViewer is not supported + * + * @throws RepositoryException + */ + public BlameViewer getBlameViewer(Repository repository) + throws RepositoryException; + /** * Method description * diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitBlameViewer.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitBlameViewer.java new file mode 100644 index 0000000000..e8da37d9fe --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitBlameViewer.java @@ -0,0 +1,156 @@ +/** + * 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.BlameCommand; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.blame.BlameResult; +import org.eclipse.jgit.lib.PersonIdent; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import sonia.scm.util.AssertUtil; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; +import java.io.IOException; + +import java.util.ArrayList; +import java.util.List; + +/** + * Class description + * + * + * @version Enter version here..., 11/09/14 + * @author Enter your name here... + */ +public class GitBlameViewer implements BlameViewer +{ + + /** the logger for GitChangesetViewer */ + private static final Logger logger = + LoggerFactory.getLogger(GitChangesetViewer.class); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param handler + * @param repository + */ + public GitBlameViewer(GitRepositoryHandler handler, Repository repository) + { + this.handler = handler; + this.repository = repository; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param revision + * @param path + * + * @return + */ + @Override + public BlamePagingResult getBlame(String revision, String path) + { + BlameResult blameResult = null; + BlamePagingResult blamePagingResult = null; + org.eclipse.jgit.lib.Repository gr = null; + File directory = handler.getDirectory(repository); + Git git = null; + + try + { + gr = GitUtil.open(directory); + git = new Git(gr); + + BlameCommand blame = git.blame(); + + if (path != null) + { + blame.setFilePath(path); + } + + blameResult = blame.call(); + AssertUtil.assertIsNotNull(blameResult); + + List blameLines = new ArrayList(); + int total = blameResult.getResultContents().size(); + + for (int i = 0; i < total; i++) + { + PersonIdent author = blameResult.getSourceAuthor(i); + BlameLine blameLine = new BlameLine(); + + blameLine.setLineNumber(i); + blameLine.setName(author.getName()); + blameLine.setEmailAddress(author.getEmailAddress()); + blameLine.setWhen(author.getWhen()); + + String content = blameResult.getResultContents().getString(i); + + blameLine.setCode(content); + blameLines.add(blameLine); + } + + blamePagingResult = new BlamePagingResult(total, blameLines); + } + catch (IOException ex) + { + logger.error("could not open repository", ex); + } + + return blamePagingResult; + } + + //~--- 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 index 0b2dfa2b55..07f642109d 100644 --- 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 @@ -88,6 +88,37 @@ public class GitRepositoryHandler //~--- get methods ---------------------------------------------------------- + /** + * Method description + * + * + * @param repository + * + * @return + */ + @Override + public BlameViewer getBlameViewer(Repository repository) + { + GitBlameViewer blameViewer = null; + + AssertUtil.assertIsNotNull(repository); + + String type = repository.getType(); + + AssertUtil.assertIsNotEmpty(type); + + if (TYPE_NAME.equals(type)) + { + blameViewer = new GitBlameViewer(this, repository); + } + else + { + throw new IllegalArgumentException("git repository is required"); + } + + return blameViewer; + } + /** * Method description * 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 index 2122ca5149..93dd058c7d 100644 --- 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 @@ -187,6 +187,20 @@ public class HgRepositoryHandler //~--- get methods ---------------------------------------------------------- + /** + * Method description + * + * + * @param repository + * + * @return + */ + @Override + public BlameViewer getBlameViewer(Repository repository) + { + return null; + } + /** * Method description * diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnBlameViewer.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnBlameViewer.java new file mode 100644 index 0000000000..ef0ef9d28a --- /dev/null +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnBlameViewer.java @@ -0,0 +1,161 @@ +/** + * 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.SVNURL; +import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager; +import org.tmatesoft.svn.core.io.SVNRepository; +import org.tmatesoft.svn.core.io.SVNRepositoryFactory; +import org.tmatesoft.svn.core.wc.ISVNAnnotateHandler; +import org.tmatesoft.svn.core.wc.SVNLogClient; +import org.tmatesoft.svn.core.wc.SVNRevision; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * Class description + * + * + * @version Enter version here..., 11/09/14 + * @author Enter your name here... + */ +public class SvnBlameViewer implements BlameViewer +{ + + /** the logger for SvnChangesetViewer */ + private static final Logger logger = + LoggerFactory.getLogger(SvnChangesetViewer.class); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param handler + * @param repository + */ + public SvnBlameViewer(SvnRepositoryHandler handler, Repository repository) + { + this.handler = handler; + this.repository = repository; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param revision + * @param path + * + * @return + */ + @Override + public BlamePagingResult getBlame(String revision, String path) + { + final List blameLines = new ArrayList(); + File directory = handler.getDirectory(repository); + SVNRepository repository = null; + SVNURL svnurl = null; + int total = 0; + + try + { + svnurl = SVNURL.fromFile(new File(directory, path)); + repository = SVNRepositoryFactory.create(SVNURL.fromFile(directory)); + + ISVNAuthenticationManager svnManager = + repository.getAuthenticationManager(); + SVNLogClient svnLogClient = new SVNLogClient(svnManager, null); + + svnLogClient.doAnnotate(svnurl, SVNRevision.HEAD, SVNRevision.HEAD, + SVNRevision.HEAD, new ISVNAnnotateHandler() + { + @Override + public void handleLine(Date date, long revision, String author, + String line) + throws SVNException + { + + // Not Used + } + @Override + public void handleLine(Date date, long revision, String author, + String line, Date mergedDate, + long mergedRevision, String mergedAuthor, + String mergedPath, int lineNumber) + throws SVNException + { + blameLines.add(new BlameLine(null, author, date, line, lineNumber)); + } + @Override + public boolean handleRevision(Date date, long revision, String author, + File contents) + throws SVNException + { + return false; + } + @Override + public void handleEOF() {} + }); + } + catch (Exception ex) {} + + total = blameLines.get(blameLines.size() - 1).getLineNumber(); + + return new BlamePagingResult(total, blameLines); + } + + //~--- 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 index ac1fb74268..868174843d 100644 --- 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 @@ -144,7 +144,29 @@ public class SvnRepositoryHandler return changesetViewer; } - /** + @Override + public BlameViewer getBlameViewer(Repository repository) { + SvnBlameViewer blameViewer = null; + + AssertUtil.assertIsNotNull(repository); + + String type = repository.getType(); + + AssertUtil.assertIsNotEmpty(type); + + if (TYPE_NAME.equals(type)) + { + blameViewer = new SvnBlameViewer(this, repository); + } + else + { + throw new IllegalArgumentException("svn repository is required"); + } + + return blameViewer; + } + + /** * Method description * * diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java index 343db97b28..64f349e5c4 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java @@ -44,6 +44,8 @@ import org.slf4j.LoggerFactory; import sonia.scm.NotSupportedFeatuerException; import sonia.scm.config.ScmConfiguration; +import sonia.scm.repository.BlamePagingResult; +import sonia.scm.repository.BlameViewerUtil; import sonia.scm.repository.BrowserResult; import sonia.scm.repository.ChangesetPagingResult; import sonia.scm.repository.ChangesetViewerUtil; @@ -59,6 +61,7 @@ import sonia.scm.repository.RepositoryHandler; import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.RepositoryNotFoundException; import sonia.scm.repository.RevisionNotFoundException; +import sonia.scm.util.AssertUtil; import sonia.scm.util.HttpUtil; import sonia.scm.web.security.WebSecurityContext; @@ -116,7 +119,8 @@ public class RepositoryResource ScmConfiguration configuration, RepositoryManager repositoryManager, Provider securityContextProvider, ChangesetViewerUtil changesetViewerUtil, - RepositoryBrowserUtil repositoryBrowserUtil) + RepositoryBrowserUtil repositoryBrowserUtil, + BlameViewerUtil blameViewerUtil) { super(repositoryManager); this.configuration = configuration; @@ -124,6 +128,7 @@ public class RepositoryResource this.securityContextProvider = securityContextProvider; this.changesetViewerUtil = changesetViewerUtil; this.repositoryBrowserUtil = repositoryBrowserUtil; + this.blameViewerUtil = blameViewerUtil; setDisableCache(false); } @@ -224,6 +229,37 @@ public class RepositoryResource return response; } + + @GET + @Path("{id}/blame") + public Response blame(@PathParam("id") String id, + @QueryParam("revision") String revision, + @QueryParam("path") String path) + { + Response response = null; + + try { + AssertUtil.assertIsNotNull(path); + BlamePagingResult blamePagingResult = blameViewerUtil.getBlame(id, revision, path); + + if (blamePagingResult != null) { + response = Response.ok(blamePagingResult).build(); + } + else + { + response = Response.ok().build(); + } + } catch (IllegalStateException ex) { + response = Response.status(Response.Status.NOT_FOUND).build(); + } catch (RepositoryException ex) { + response = Response.status(Response.Status.NOT_FOUND).build(); + } catch (NotSupportedFeatuerException ex) { + response = Response.status(Response.Status.BAD_REQUEST).build(); + } + + return response; + } + /** * Method description @@ -512,10 +548,13 @@ public class RepositoryResource /** Field description */ private RepositoryBrowserUtil repositoryBrowserUtil; + + /** Field description */ + private BlameViewerUtil blameViewerUtil; /** Field description */ private RepositoryManager repositoryManager; - + /** Field description */ private Provider securityContextProvider; } diff --git a/scm-webapp/src/main/java/sonia/scm/repository/xml/XmlRepositoryManager.java b/scm-webapp/src/main/java/sonia/scm/repository/xml/XmlRepositoryManager.java index 8968174f91..b32392f62f 100644 --- a/scm-webapp/src/main/java/sonia/scm/repository/xml/XmlRepositoryManager.java +++ b/scm-webapp/src/main/java/sonia/scm/repository/xml/XmlRepositoryManager.java @@ -47,6 +47,7 @@ import sonia.scm.HandlerEvent; import sonia.scm.SCMContextProvider; import sonia.scm.Type; import sonia.scm.repository.AbstractRepositoryManager; +import sonia.scm.repository.BlameViewer; import sonia.scm.repository.ChangesetViewer; import sonia.scm.repository.PermissionType; import sonia.scm.repository.PermissionUtil; @@ -549,7 +550,16 @@ public class XmlRepositoryManager extends AbstractRepositoryManager return getHandler(repository).getChangesetViewer(repository); } - /** + @Override + public BlameViewer getBlameViewer(Repository repository) + throws RepositoryException + { + AssertUtil.assertIsNotNull(repository); + isReader(repository); + return getHandler(repository).getBlameViewer(repository); + } + + /** * Method description * *