From a6ecd7ba0042ed635fd46b21782bfa3699370fe3 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Sat, 1 Nov 2014 12:32:21 +0100 Subject: [PATCH] implement push/pull for remote urls --- ...java => AbstractGitPushOrPullCommand.java} | 81 +++++++- .../scm/repository/spi/GitPullCommand.java | 190 ++++++++++++++++-- .../scm/repository/spi/GitPushCommand.java | 28 +-- .../repository/spi/GitPushCommandTest.java | 6 - .../spi/AbstractHgPushOrPullCommand.java | 99 +++++++++ .../scm/repository/spi/HgPullCommand.java | 29 +-- .../scm/repository/spi/HgPushCommand.java | 29 +-- 7 files changed, 396 insertions(+), 66 deletions(-) rename scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/{AbstractPushOrPullCommand.java => AbstractGitPushOrPullCommand.java} (76%) create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/AbstractHgPushOrPullCommand.java diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/AbstractPushOrPullCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/AbstractGitPushOrPullCommand.java similarity index 76% rename from scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/AbstractPushOrPullCommand.java rename to scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/AbstractGitPushOrPullCommand.java index dfddfc1cc0..04838403f3 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/AbstractPushOrPullCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/AbstractGitPushOrPullCommand.java @@ -48,6 +48,7 @@ import org.eclipse.jgit.transport.RemoteRefUpdate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.RepositoryException; //~--- JDK imports ------------------------------------------------------------ @@ -61,17 +62,17 @@ import java.util.Collection; * * @author Sebastian Sdorra */ -public abstract class AbstractPushOrPullCommand extends AbstractGitCommand +public abstract class AbstractGitPushOrPullCommand extends AbstractGitCommand { /** Field description */ private static final String SCHEME = "scm://"; /** - * the logger for AbstractPushOrPullCommand + * the logger for AbstractGitPushOrPullCommand */ private static final Logger logger = - LoggerFactory.getLogger(AbstractPushOrPullCommand.class); + LoggerFactory.getLogger(AbstractGitPushOrPullCommand.class); //~--- constructors --------------------------------------------------------- @@ -79,36 +80,38 @@ public abstract class AbstractPushOrPullCommand extends AbstractGitCommand * Constructs ... * * + * @param handler * @param context * @param repository */ - public AbstractPushOrPullCommand(GitContext context, - sonia.scm.repository.Repository repository) + protected AbstractGitPushOrPullCommand(GitRepositoryHandler handler, + GitContext context, sonia.scm.repository.Repository repository) { super(context, repository); + this.handler = handler; } //~--- methods -------------------------------------------------------------- /** * Method description - * + * * @param source - * @param target + * @param remoteUrl * * @return * * @throws IOException * @throws RepositoryException */ - protected long push(Repository source, File target) + protected long push(Repository source, String remoteUrl) throws IOException, RepositoryException { Git git = Git.wrap(source); org.eclipse.jgit.api.PushCommand push = git.push(); push.setPushAll().setPushTags(); - push.setRemote(SCHEME.concat(target.getAbsolutePath())); + push.setRemote(remoteUrl); long counter = -1; @@ -158,6 +161,61 @@ public abstract class AbstractPushOrPullCommand extends AbstractGitCommand return remoteRepository; } + /** + * Method description + * + * + * @param request + * + * @return + */ + protected String getRemoteUrl(RemoteCommandRequest request) + { + String url; + sonia.scm.repository.Repository remRepo = request.getRemoteRepository(); + + if (remRepo != null) + { + url = getRemoteUrl(remRepo); + } + else if (request.getRemoteUrl() != null) + { + url = request.getRemoteUrl().toExternalForm(); + } + else + { + throw new IllegalArgumentException("repository or url is requiered"); + } + + return url; + } + + /** + * Method description + * + * + * @param directory + * + * @return + */ + protected String getRemoteUrl(File directory) + { + return SCHEME.concat(directory.getAbsolutePath()); + } + + /** + * Method description + * + * + * @param repository + * + * @return + */ + protected String getRemoteUrl(sonia.scm.repository.Repository repository) + { + return getRemoteUrl(handler.getDirectory(repository)); + } + //~--- methods -------------------------------------------------------------- /** @@ -231,4 +289,9 @@ public abstract class AbstractPushOrPullCommand extends AbstractGitCommand return counter; } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + protected GitRepositoryHandler handler; } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitPullCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitPullCommand.java index ac2ebbfb77..0c4795c619 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitPullCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitPullCommand.java @@ -36,8 +36,19 @@ package sonia.scm.repository.spi; //~--- non-JDK imports -------------------------------------------------------- import com.google.common.base.Preconditions; +import com.google.common.collect.Iterables; import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.transport.FetchResult; +import org.eclipse.jgit.transport.RefSpec; +import org.eclipse.jgit.transport.TagOpt; +import org.eclipse.jgit.transport.TrackingRefUpdate; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.GitUtil; @@ -50,27 +61,37 @@ import sonia.scm.repository.api.PullResponse; import java.io.File; import java.io.IOException; +import java.net.URL; + /** * * @author Sebastian Sdorra */ -public class GitPullCommand extends AbstractPushOrPullCommand +public class GitPullCommand extends AbstractGitPushOrPullCommand implements PullCommand { + /** Field description */ + private static final String REF_SPEC = "refs/heads/*:refs/heads/*"; + + /** Field description */ + private static final Logger logger = + LoggerFactory.getLogger(GitPullCommand.class); + + //~--- constructors --------------------------------------------------------- + /** * Constructs ... * * - * @param repositoryHandler + * @param handler * @param context * @param repository */ - public GitPullCommand(GitRepositoryHandler repositoryHandler, - GitContext context, Repository repository) + public GitPullCommand(GitRepositoryHandler handler, GitContext context, + Repository repository) { - super(context, repository); - this.repositoryHandler = repositoryHandler; + super(handler, context, repository); } //~--- methods -------------------------------------------------------------- @@ -90,18 +111,127 @@ public class GitPullCommand extends AbstractPushOrPullCommand public PullResponse pull(PullCommandRequest request) throws IOException, RepositoryException { - Repository sourceRepository = getRemoteRepository(request); + PullResponse response; + Repository sourceRepository = request.getRemoteRepository(); - File sourceDirectory = repositoryHandler.getDirectory(sourceRepository); + if (sourceRepository != null) + { + response = pullFromScmRepository(sourceRepository); + } + else if (request.getRemoteUrl() != null) + { + response = pullFromUrl(request.getRemoteUrl()); + } + else + { + throw new IllegalArgumentException("repository or url is required"); + } + + return response; + } + + /** + * Method description + * + * + * @param git + * @param result + * @param fetch + * + * @return + * + * @throws RepositoryException + */ + private PullResponse convert(Git git, FetchResult fetch) + throws RepositoryException + { + long counter = 0l; + + for (TrackingRefUpdate tru : fetch.getTrackingRefUpdates()) + { + counter += count(git, tru); + } + + return new PullResponse(counter); + } + + /** + * Method description + * + * + * @param git + * @param tru + * + * @return + */ + private long count(Git git, TrackingRefUpdate tru) + { + long counter = 0; + + try + { + org.eclipse.jgit.api.LogCommand log = git.log(); + ObjectId oldId = tru.getOldObjectId(); + + if (oldId != null) + { + log.not(oldId); + } + + ObjectId newId = tru.getNewObjectId(); + + if (newId != null) + { + log.add(newId); + + Iterable commits = log.call(); + + if (commits != null) + { + counter += Iterables.size(commits); + } + } + else + { + logger.warn("update without new object id"); + } + + } + catch (Exception ex) + { + logger.error("could not count pushed/pulled changesets", ex); + } + + return counter; + } + + /** + * Method description + * + * + * @param sourceRepository + * + * @return + * + * @throws IOException + * @throws RepositoryException + */ + private PullResponse pullFromScmRepository(Repository sourceRepository) + throws IOException, RepositoryException + { + File sourceDirectory = handler.getDirectory(sourceRepository); Preconditions.checkArgument(sourceDirectory.exists(), "source repository directory does not exists"); - File targetDirectory = repositoryHandler.getDirectory(repository); + File targetDirectory = handler.getDirectory(repository); Preconditions.checkArgument(sourceDirectory.exists(), "target repository directory does not exists"); + logger.debug("pull changes from {} to {}", + sourceDirectory.getAbsolutePath(), repository.getId()); + PullResponse response = null; org.eclipse.jgit.lib.Repository source = null; @@ -109,7 +239,7 @@ public class GitPullCommand extends AbstractPushOrPullCommand try { source = Git.open(sourceDirectory).getRepository(); - response = new PullResponse(push(source, targetDirectory)); + response = new PullResponse(push(source, getRemoteUrl(targetDirectory))); } finally { @@ -119,8 +249,42 @@ public class GitPullCommand extends AbstractPushOrPullCommand return response; } - //~--- fields --------------------------------------------------------------- + /** + * Method description + * + * + * @param url + * + * @return + * + * @throws IOException + * @throws RepositoryException + */ + private PullResponse pullFromUrl(URL url) + throws IOException, RepositoryException + { + logger.debug("pull changes from {} to {}", url, repository.getId()); - /** Field description */ - private GitRepositoryHandler repositoryHandler; + PullResponse response; + Git git = Git.wrap(open()); + + try + { + //J- + FetchResult result = git.fetch() + .setRefSpecs(new RefSpec(REF_SPEC)) + .setRemote(url.toExternalForm()) + .setTagOpt(TagOpt.FETCH_TAGS) + .call(); + //J+ + + response = convert(git, result); + } + catch (GitAPIException ex) + { + throw new RepositoryException("error durring pull", ex); + } + + return response; + } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitPushCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitPushCommand.java index d291860b6d..c64465194a 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitPushCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitPushCommand.java @@ -30,11 +30,13 @@ */ + package sonia.scm.repository.spi; //~--- non-JDK imports -------------------------------------------------------- -import com.google.common.base.Preconditions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.Repository; @@ -43,17 +45,22 @@ import sonia.scm.repository.api.PushResponse; //~--- JDK imports ------------------------------------------------------------ -import java.io.File; import java.io.IOException; /** * * @author Sebastian Sdorra */ -public class GitPushCommand extends AbstractPushOrPullCommand +public class GitPushCommand extends AbstractGitPushOrPullCommand implements PushCommand { + /** Field description */ + private static final Logger logger = + LoggerFactory.getLogger(GitPushCommand.class); + + //~--- constructors --------------------------------------------------------- + /** * Constructs ... * @@ -65,7 +72,7 @@ public class GitPushCommand extends AbstractPushOrPullCommand public GitPushCommand(GitRepositoryHandler handler, GitContext context, Repository repository) { - super(context, repository); + super(handler, context, repository); this.handler = handler; } @@ -86,17 +93,10 @@ public class GitPushCommand extends AbstractPushOrPullCommand public PushResponse push(PushCommandRequest request) throws IOException, RepositoryException { - Repository target = getRemoteRepository(request); - File targetDirectory = handler.getDirectory(target); + String remoteUrl = getRemoteUrl(request); - Preconditions.checkArgument(targetDirectory.exists(), - "target repository directory does not exists"); + logger.debug("push changes from {} to {}", repository.getId(), remoteUrl); - return new PushResponse(push(open(), targetDirectory)); + return new PushResponse(push(open(), remoteUrl)); } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private GitRepositoryHandler handler; } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitPushCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitPushCommandTest.java index 83fb7e61e5..bf82193e84 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitPushCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitPushCommandTest.java @@ -37,7 +37,6 @@ package sonia.scm.repository.spi; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.revwalk.RevCommit; -import org.eclipse.jgit.transport.ScmTransportProtocol; import org.junit.Test; @@ -106,9 +105,4 @@ public class GitPushCommandTest extends AbstractRemoteCommandTestBase return new GitPushCommand(handler, new GitContext(outgoingDirectory), outgoingRepository); } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private ScmTransportProtocol proto; } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/AbstractHgPushOrPullCommand.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/AbstractHgPushOrPullCommand.java new file mode 100644 index 0000000000..a3b159fbfb --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/AbstractHgPushOrPullCommand.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.spi; + +//~--- non-JDK imports -------------------------------------------------------- + +import sonia.scm.repository.HgRepositoryHandler; +import sonia.scm.repository.Repository; + +/** + * + * @author Sebastian Sdorra + */ +public class AbstractHgPushOrPullCommand extends AbstractCommand +{ + + /** + * Constructs ... + * + * + * @param handler + * @param context + * @param repository + */ + protected AbstractHgPushOrPullCommand(HgRepositoryHandler handler, + HgCommandContext context, Repository repository) + { + super(context, repository); + this.handler = handler; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param request + * + * @return + */ + protected String getRemoteUrl(RemoteCommandRequest request) + { + String url; + Repository repo = request.getRemoteRepository(); + + if (repo != null) + { + url = + handler.getDirectory(request.getRemoteRepository()).getAbsolutePath(); + } + else if (request.getRemoteUrl() != null) + { + url = request.getRemoteUrl().toExternalForm(); + } + else + { + throw new IllegalArgumentException("url or repository is required"); + } + + return url; + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + protected final HgRepositoryHandler handler; +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgPullCommand.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgPullCommand.java index 0553fa667d..de407b621d 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgPullCommand.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgPullCommand.java @@ -30,6 +30,7 @@ */ + package sonia.scm.repository.spi; //~--- non-JDK imports -------------------------------------------------------- @@ -37,6 +38,9 @@ package sonia.scm.repository.spi; import com.aragost.javahg.Changeset; import com.aragost.javahg.commands.ExecutionException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryException; @@ -44,7 +48,6 @@ import sonia.scm.repository.api.PullResponse; //~--- JDK imports ------------------------------------------------------------ -import java.io.File; import java.io.IOException; import java.util.Collections; @@ -54,9 +57,16 @@ import java.util.List; * * @author Sebastian Sdorra */ -public class HgPullCommand extends AbstractCommand implements PullCommand +public class HgPullCommand extends AbstractHgPushOrPullCommand + implements PullCommand { + /** Field description */ + private static final Logger logger = + LoggerFactory.getLogger(HgPullCommand.class); + + //~--- constructors --------------------------------------------------------- + /** * Constructs ... * @@ -68,8 +78,7 @@ public class HgPullCommand extends AbstractCommand implements PullCommand public HgPullCommand(HgRepositoryHandler handler, HgCommandContext context, Repository repository) { - super(context, repository); - this.handler = handler; + super(handler, context, repository); } //~--- methods -------------------------------------------------------------- @@ -89,14 +98,15 @@ public class HgPullCommand extends AbstractCommand implements PullCommand public PullResponse pull(PullCommandRequest request) throws RepositoryException, IOException { - File remoteRepository = handler.getDirectory(request.getRemoteRepository()); + String url = getRemoteUrl(request); + + logger.debug("pull changes from {} to {}", url, getRepository().getId()); List result = Collections.EMPTY_LIST; try { - result = com.aragost.javahg.commands.PullCommand.on(open()).execute( - remoteRepository.getAbsolutePath()); + result = com.aragost.javahg.commands.PullCommand.on(open()).execute(url); } catch (ExecutionException ex) { @@ -105,9 +115,4 @@ public class HgPullCommand extends AbstractCommand implements PullCommand return new PullResponse(result.size()); } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private HgRepositoryHandler handler; } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgPushCommand.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgPushCommand.java index 5025914484..69644efe27 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgPushCommand.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgPushCommand.java @@ -30,6 +30,7 @@ */ + package sonia.scm.repository.spi; //~--- non-JDK imports -------------------------------------------------------- @@ -37,6 +38,9 @@ package sonia.scm.repository.spi; import com.aragost.javahg.Changeset; import com.aragost.javahg.commands.ExecutionException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryException; @@ -44,7 +48,6 @@ import sonia.scm.repository.api.PushResponse; //~--- JDK imports ------------------------------------------------------------ -import java.io.File; import java.io.IOException; import java.util.Collections; @@ -54,9 +57,16 @@ import java.util.List; * * @author Sebastian Sdorra */ -public class HgPushCommand extends AbstractCommand implements PushCommand +public class HgPushCommand extends AbstractHgPushOrPullCommand + implements PushCommand { + /** Field description */ + private static final Logger logger = + LoggerFactory.getLogger(HgPushCommand.class); + + //~--- constructors --------------------------------------------------------- + /** * Constructs ... * @@ -68,8 +78,7 @@ public class HgPushCommand extends AbstractCommand implements PushCommand public HgPushCommand(HgRepositoryHandler handler, HgCommandContext context, Repository repository) { - super(context, repository); - this.handler = handler; + super(handler, context, repository); } //~--- methods -------------------------------------------------------------- @@ -89,14 +98,15 @@ public class HgPushCommand extends AbstractCommand implements PushCommand public PushResponse push(PushCommandRequest request) throws RepositoryException, IOException { - File remoteRepository = handler.getDirectory(request.getRemoteRepository()); + String url = getRemoteUrl(request); + + logger.debug("push changes from {} to {}", getRepository().getId(), url); List result = Collections.EMPTY_LIST; try { - result = com.aragost.javahg.commands.PushCommand.on(open()).execute( - remoteRepository.getAbsolutePath()); + result = com.aragost.javahg.commands.PushCommand.on(open()).execute(url); } catch (ExecutionException ex) { @@ -105,9 +115,4 @@ public class HgPushCommand extends AbstractCommand implements PushCommand return new PushResponse(result.size()); } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private HgRepositoryHandler handler; }