From 01534177c290407f1c61c70145c64c789491575f Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Sat, 7 Jan 2012 15:25:22 +0100 Subject: [PATCH] added browser support for git submodules --- .../scm/repository/GitRepositoryBrowser.java | 142 +++++++++++++++++- .../scm/repository/GitSubModuleParser.java | 109 ++++++++++++++ .../repository/GitSubModuleParserTest.java | 122 +++++++++++++++ .../sonia/scm/repository/gitmodules-001 | 6 + 4 files changed, 374 insertions(+), 5 deletions(-) create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitSubModuleParser.java create mode 100644 scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitSubModuleParserTest.java create mode 100644 scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/repository/gitmodules-001 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 index 368c18704f..d2bfc99856 100644 --- 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 @@ -54,12 +54,15 @@ import sonia.scm.util.Util; //~--- JDK imports ------------------------------------------------------------ +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; /** * @@ -68,6 +71,9 @@ import java.util.List; public class GitRepositoryBrowser implements RepositoryBrowser { + /** Field description */ + public static final String PATH_MODULES = ".gitmodules"; + /** the logger for GitRepositoryBrowser */ private static final Logger logger = LoggerFactory.getLogger(GitRepositoryBrowser.class); @@ -98,7 +104,6 @@ public class GitRepositoryBrowser implements RepositoryBrowser * @param path * @param output * - * * @throws IOException * @throws RepositoryException */ @@ -108,6 +113,37 @@ public class GitRepositoryBrowser implements RepositoryBrowser { File directory = handler.getDirectory(repository); org.eclipse.jgit.lib.Repository repo = GitUtil.open(directory); + + try + { + ObjectId revId = GitUtil.getRevisionId(repo, revision); + + getContent(repo, revId, path, output); + } + finally + { + GitUtil.close(repo); + } + } + + /** + * Method description + * + * + * + * @param repo + * @param revId + * @param path + * @param output + * + * + * @throws IOException + * @throws RepositoryException + */ + public void getContent(org.eclipse.jgit.lib.Repository repo, ObjectId revId, + String path, OutputStream output) + throws IOException, RepositoryException + { TreeWalk treeWalk = null; RevWalk revWalk = null; @@ -116,8 +152,6 @@ public class GitRepositoryBrowser implements RepositoryBrowser treeWalk = new TreeWalk(repo); treeWalk.setRecursive(Util.nonNull(path).contains("/")); - ObjectId revId = GitUtil.getRevisionId(repo, revision); - if (logger.isDebugEnabled()) { logger.debug("load content for {} at {}", path, revId.name()); @@ -166,7 +200,6 @@ public class GitRepositoryBrowser implements RepositoryBrowser { GitUtil.release(revWalk); GitUtil.release(treeWalk); - GitUtil.close(repo); } } @@ -232,6 +265,64 @@ public class GitRepositoryBrowser implements RepositoryBrowser //~--- methods -------------------------------------------------------------- + /** + * Method description + * + * + * @param files + * @param repo + * @param revId + * @param path + * + * @throws IOException + * @throws RepositoryException + */ + private void appendSubModules(List files, + org.eclipse.jgit.lib.Repository repo, + ObjectId revId, String path) + throws IOException, RepositoryException + { + path = Util.nonNull(path); + + Map subRepositories = getSubRepositories(repo, + revId); + + if (subRepositories != null) + { + for (Entry e : subRepositories.entrySet()) + { + String p = e.getKey(); + + if (p.startsWith(path)) + { + p = p.substring(path.length()); + + if (p.startsWith("/")) + { + p = p.substring(1); + } + + if (p.endsWith("/")) + { + p = p.substring(0, p.length() - 1); + } + + if (!p.contains("/")) + { + FileObject fo = new FileObject(); + + fo.setDirectory(true); + fo.setPath(path); + fo.setName(p); + fo.setSubRepository(e.getValue()); + + files.add(fo); + } + } + } + } + } + /** * Method description * @@ -349,10 +440,11 @@ public class GitRepositoryBrowser implements RepositoryBrowser * @return * * @throws IOException + * @throws RepositoryException */ private BrowserResult getResult(org.eclipse.jgit.lib.Repository repo, ObjectId revId, String path) - throws IOException + throws IOException, RepositoryException { BrowserResult result = null; RevWalk revWalk = null; @@ -383,6 +475,8 @@ public class GitRepositoryBrowser implements RepositoryBrowser List files = new ArrayList(); + appendSubModules(files, repo, revId, path); + if (Util.isEmpty(path)) { while (treeWalk.next()) @@ -439,6 +533,44 @@ public class GitRepositoryBrowser implements RepositoryBrowser return result; } + /** + * Method description + * + * + * @param repo + * @param revision + * + * @return + * + * @throws IOException + * @throws RepositoryException + */ + private Map getSubRepositories( + org.eclipse.jgit.lib.Repository repo, ObjectId revision) + throws IOException, RepositoryException + { + if (logger.isDebugEnabled()) + { + logger.debug("read submodules of {} at {}", repository.getName(), + revision); + } + + Map subRepositories = null; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + try + { + getContent(repo, revision, PATH_MODULES, baos); + subRepositories = GitSubModuleParser.parse(baos.toString()); + } + catch (PathNotFoundException ex) + { + logger.trace("could not find .gitmodules", ex); + } + + return subRepositories; + } + //~--- fields --------------------------------------------------------------- /** Field description */ diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitSubModuleParser.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitSubModuleParser.java new file mode 100644 index 0000000000..48492e24ec --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitSubModuleParser.java @@ -0,0 +1,109 @@ +/** + * 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 java.util.HashMap; +import java.util.Map; +import java.util.Scanner; + +/** + * + * @author Sebastian Sdorra + */ +public class GitSubModuleParser +{ + + /** + * //~--- methods -------------------------------------------------------------- + * + * + * Method description + * + * + * @param content + * + * @return + */ + public static Map parse(String content) + { + Map subRepositories = new HashMap(); + Scanner scanner = new Scanner(content); + SubRepository repository = null; + + while (scanner.hasNextLine()) + { + String line = scanner.nextLine(); + + if (Util.isNotEmpty(line)) + { + line = line.trim(); + + if (line.startsWith("[") && line.endsWith("]")) + { + repository = new SubRepository(); + } + else if (line.startsWith("path")) + { + subRepositories.put(getValue(line), repository); + } + else if (line.startsWith("url")) + { + repository.setRepositoryUrl(getValue(line)); + } + } + } + + return subRepositories; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param line + * + * @return + */ + private static String getValue(String line) + { + return line.split("=")[1].trim(); + } +} diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitSubModuleParserTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitSubModuleParserTest.java new file mode 100644 index 0000000000..c3593113f2 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitSubModuleParserTest.java @@ -0,0 +1,122 @@ +/** + * 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.junit.Test; + +import static org.junit.Assert.*; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.IOException; +import java.io.InputStream; + +import java.util.Map; + +/** + * + * @author Sebastian Sdorra + */ +public class GitSubModuleParserTest +{ + + /** Field description */ + public static final String GITMODULES_001 = + "/sonia/scm/repository/gitmodules-001"; + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @throws IOException + */ + @Test + public void testParse() throws IOException + { + Map subRepositories = + getSubRepositories(GITMODULES_001); + SubRepository repository = subRepositories.get("gerrit"); + + assertNotNull(repository); + assertNotNull(repository.getRepositoryUrl()); + assertEquals("http://localhost:8081/scm/git/gerrit", + repository.getRepositoryUrl()); + repository = subRepositories.get("git-mod-1"); + assertNotNull(repository); + assertNotNull(repository.getRepositoryUrl()); + assertEquals("http://localhost:8081/scm/git/sub/git-mod-1", + repository.getRepositoryUrl()); + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param resource + * + * @return + * + * @throws IOException + */ + private String getContent(String resource) throws IOException + { + InputStream input = + GitSubModuleParserTest.class.getResourceAsStream(resource); + byte[] buffer = new byte[input.available()]; + + input.read(buffer); + + return new String(buffer); + } + + /** + * Method description + * + * + * @param resource + * + * @return + * + * @throws IOException + */ + private Map getSubRepositories(String resource) + throws IOException + { + return GitSubModuleParser.parse(getContent(resource)); + } +} diff --git a/scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/repository/gitmodules-001 b/scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/repository/gitmodules-001 new file mode 100644 index 0000000000..d93356681c --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/repository/gitmodules-001 @@ -0,0 +1,6 @@ +[submodule "gerrit"] + path = gerrit + url = http://localhost:8081/scm/git/gerrit +[submodule "git-mod-1"] + path = git-mod-1 + url = http://localhost:8081/scm/git/sub/git-mod-1 \ No newline at end of file