mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-03-06 04:10:52 +01:00
Proxy support for pull, push and mirror commands (#1773)
Apply proxy support for jGit by extracting the required functionality from the DefaultAdvancedHttpClient into its own class HttpURLConnectionFactory. This new class is now used by the DefaultAdvancedHttpClient and jGit. The HttpURLConnection also fixes proxy server authentication, which was non functional in DefaultAdvancedHttpClient. The proxy support for SVNKit is implemented by using the provided method of the BasicAuthenticationManager. For mercurial the support is configured by writing the required settings to a temporary hgrc file.
This commit is contained in:
@@ -26,16 +26,20 @@ package sonia.scm.repository.spi;
|
||||
|
||||
import com.aragost.javahg.Changeset;
|
||||
import com.aragost.javahg.commands.CommitCommand;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.ContextEntry;
|
||||
import sonia.scm.repository.Branch;
|
||||
import sonia.scm.repository.HgRepositoryHandler;
|
||||
import sonia.scm.repository.InternalRepositoryException;
|
||||
import sonia.scm.repository.api.BranchRequest;
|
||||
import sonia.scm.repository.work.WorkingCopy;
|
||||
import sonia.scm.user.User;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* Mercurial implementation of the {@link BranchCommand}.
|
||||
* Note that this creates an empty commit to "persist" the new branch.
|
||||
@@ -44,6 +48,12 @@ public class HgBranchCommand extends AbstractWorkingCopyCommand implements Branc
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(HgBranchCommand.class);
|
||||
|
||||
@Inject
|
||||
HgBranchCommand(HgCommandContext context, HgRepositoryHandler handler) {
|
||||
this(context, handler.getWorkingCopyFactory());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
HgBranchCommand(HgCommandContext context, HgWorkingCopyFactory workingCopyFactory) {
|
||||
super(context, workingCopyFactory);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.repository.spi;
|
||||
|
||||
import sonia.scm.repository.HgConfigResolver;
|
||||
import sonia.scm.repository.HgRepositoryFactory;
|
||||
import sonia.scm.repository.Repository;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class HgCommandContextFactory {
|
||||
|
||||
private final HgConfigResolver configResolver;
|
||||
private final HgRepositoryFactory repositoryFactory;
|
||||
|
||||
@Inject
|
||||
public HgCommandContextFactory(HgConfigResolver configResolver, HgRepositoryFactory repositoryFactory) {
|
||||
this.configResolver = configResolver;
|
||||
this.repositoryFactory = repositoryFactory;
|
||||
}
|
||||
|
||||
public HgCommandContext create(Repository repository) {
|
||||
return new HgCommandContext(configResolver, repositoryFactory, repository);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -33,6 +33,7 @@ import sonia.scm.repository.HgRepositoryHandler;
|
||||
import sonia.scm.repository.InternalRepositoryException;
|
||||
import sonia.scm.repository.spi.javahg.HgIncomingChangesetCommand;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -58,6 +59,7 @@ public class HgIncomingCommand extends AbstractCommand
|
||||
* @param context
|
||||
* @param handler
|
||||
*/
|
||||
@Inject
|
||||
HgIncomingCommand(HgCommandContext context, HgRepositoryHandler handler)
|
||||
{
|
||||
super(context);
|
||||
@@ -87,7 +89,7 @@ public class HgIncomingCommand extends AbstractCommand
|
||||
{
|
||||
if (ex.getCommand().getReturnCode() == NO_INCOMING_CHANGESETS)
|
||||
{
|
||||
changesets = Collections.EMPTY_LIST;
|
||||
changesets = Collections.emptyList();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.repository.spi;
|
||||
|
||||
import sonia.scm.io.INIConfiguration;
|
||||
import sonia.scm.io.INIConfigurationReader;
|
||||
import sonia.scm.io.INIConfigurationWriter;
|
||||
import sonia.scm.io.INISection;
|
||||
import sonia.scm.repository.HgRepositoryHandler;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
public class HgIniConfigurator {
|
||||
|
||||
private final HgCommandContext context;
|
||||
private static final String AUTH_SECTION = "auth";
|
||||
|
||||
public HgIniConfigurator(HgCommandContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public void addAuthenticationConfig(RemoteCommandRequest request, String url) throws IOException {
|
||||
INIConfiguration ini = readIniConfiguration();
|
||||
INISection authSection = ini.getSection(AUTH_SECTION);
|
||||
if (authSection == null) {
|
||||
authSection = new INISection(AUTH_SECTION);
|
||||
ini.addSection(authSection);
|
||||
}
|
||||
URI parsedUrl = URI.create(url);
|
||||
authSection.setParameter("import.prefix", parsedUrl.getHost());
|
||||
authSection.setParameter("import.schemes", parsedUrl.getScheme());
|
||||
authSection.setParameter("import.username", request.getUsername());
|
||||
authSection.setParameter("import.password", request.getPassword());
|
||||
writeIniConfiguration(ini);
|
||||
}
|
||||
|
||||
public void removeAuthenticationConfig() throws IOException {
|
||||
INIConfiguration ini = readIniConfiguration();
|
||||
ini.removeSection(AUTH_SECTION);
|
||||
writeIniConfiguration(ini);
|
||||
}
|
||||
|
||||
public INIConfiguration readIniConfiguration() throws IOException {
|
||||
return new INIConfigurationReader().read(getHgrcFile());
|
||||
}
|
||||
|
||||
public void writeIniConfiguration(INIConfiguration ini) throws IOException {
|
||||
new INIConfigurationWriter().write(ini, getHgrcFile());
|
||||
}
|
||||
|
||||
public File getHgrcFile() {
|
||||
return new File(context.getDirectory(), HgRepositoryHandler.PATH_HGRC);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import sonia.scm.repository.HgRepositoryFactory;
|
||||
import sonia.scm.repository.Person;
|
||||
import sonia.scm.repository.Repository;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
@@ -38,9 +39,10 @@ class HgLazyChangesetResolver implements Callable<Iterable<Changeset>> {
|
||||
private final HgRepositoryFactory factory;
|
||||
private final Repository repository;
|
||||
|
||||
HgLazyChangesetResolver(HgRepositoryFactory factory, Repository repository) {
|
||||
@Inject
|
||||
HgLazyChangesetResolver(HgRepositoryFactory factory, HgCommandContext context) {
|
||||
this.factory = factory;
|
||||
this.repository = repository;
|
||||
this.repository = context.getScmRepository();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -30,12 +30,15 @@ import com.aragost.javahg.commands.CommitCommand;
|
||||
import com.aragost.javahg.commands.ExecutionException;
|
||||
import com.aragost.javahg.commands.RemoveCommand;
|
||||
import com.aragost.javahg.commands.StatusCommand;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.NoChangesMadeException;
|
||||
import sonia.scm.repository.HgRepositoryHandler;
|
||||
import sonia.scm.repository.InternalRepositoryException;
|
||||
import sonia.scm.repository.work.WorkingCopy;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
@@ -48,8 +51,13 @@ public class HgModifyCommand extends AbstractWorkingCopyCommand implements Modif
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(HgModifyCommand.class);
|
||||
|
||||
@Inject
|
||||
public HgModifyCommand(HgCommandContext context, HgRepositoryHandler handler) {
|
||||
super(context, handler.getWorkingCopyFactory());
|
||||
}
|
||||
|
||||
public HgModifyCommand(HgCommandContext context, HgWorkingCopyFactory workingCopyFactory) {
|
||||
@VisibleForTesting
|
||||
HgModifyCommand(HgCommandContext context, HgWorkingCopyFactory workingCopyFactory) {
|
||||
super(context, workingCopyFactory);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ import sonia.scm.repository.HgRepositoryHandler;
|
||||
import sonia.scm.repository.InternalRepositoryException;
|
||||
import sonia.scm.repository.spi.javahg.HgOutgoingChangesetCommand;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -58,7 +59,8 @@ public class HgOutgoingCommand extends AbstractCommand
|
||||
* @param context
|
||||
* @param handler
|
||||
*/
|
||||
public HgOutgoingCommand(HgCommandContext context, HgRepositoryHandler handler)
|
||||
@Inject
|
||||
HgOutgoingCommand(HgCommandContext context, HgRepositoryHandler handler)
|
||||
{
|
||||
super(context);
|
||||
this.handler = handler;
|
||||
@@ -87,7 +89,7 @@ public class HgOutgoingCommand extends AbstractCommand
|
||||
{
|
||||
if (ex.getCommand().getReturnCode() == NO_OUTGOING_CHANGESETS)
|
||||
{
|
||||
changesets = Collections.EMPTY_LIST;
|
||||
changesets = Collections.emptyList();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -29,55 +29,58 @@ import com.aragost.javahg.commands.ExecutionException;
|
||||
import com.google.common.base.Strings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.ContextEntry;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.repository.HgRepositoryHandler;
|
||||
import sonia.scm.repository.api.ImportFailedException;
|
||||
import sonia.scm.repository.api.PullResponse;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static sonia.scm.ContextEntry.ContextBuilder.entity;
|
||||
|
||||
public class HgPullCommand extends AbstractHgPushOrPullCommand implements PullCommand {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(HgPullCommand.class);
|
||||
private final ScmEventBus eventBus;
|
||||
private final HgLazyChangesetResolver changesetResolver;
|
||||
private final HgRepositoryHookEventFactory eventFactory;
|
||||
private final TemporaryConfigFactory configFactory;
|
||||
|
||||
@Inject
|
||||
public HgPullCommand(HgRepositoryHandler handler,
|
||||
HgCommandContext context,
|
||||
ScmEventBus eventBus,
|
||||
HgLazyChangesetResolver changesetResolver,
|
||||
HgRepositoryHookEventFactory eventFactory
|
||||
HgRepositoryHookEventFactory eventFactory,
|
||||
TemporaryConfigFactory configFactory
|
||||
) {
|
||||
super(handler, context);
|
||||
this.eventBus = eventBus;
|
||||
this.changesetResolver = changesetResolver;
|
||||
this.eventFactory = eventFactory;
|
||||
this.configFactory = configFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"java:S3252"})
|
||||
public PullResponse pull(PullCommandRequest request)
|
||||
throws IOException {
|
||||
public PullResponse pull(PullCommandRequest request) throws IOException {
|
||||
String url = getRemoteUrl(request);
|
||||
HgIniConfigurator iniConfigurator = new HgIniConfigurator(getContext());
|
||||
|
||||
LOG.debug("pull changes from {} to {}", url, getContext().getScmRepository());
|
||||
|
||||
List<Changeset> result;
|
||||
|
||||
TemporaryConfigFactory.Builder builder = configFactory.withContext(context);
|
||||
if (!Strings.isNullOrEmpty(request.getUsername()) && !Strings.isNullOrEmpty(request.getPassword())) {
|
||||
iniConfigurator.addAuthenticationConfig(request, url);
|
||||
builder.withCredentials(url, request.getUsername(), request.getPassword());
|
||||
}
|
||||
|
||||
List<Changeset> result;
|
||||
|
||||
try {
|
||||
result = com.aragost.javahg.commands.PullCommand.on(open()).execute(url);
|
||||
result = builder.call(() -> com.aragost.javahg.commands.PullCommand.on(open()).execute(url));
|
||||
} catch (ExecutionException ex) {
|
||||
throw new ImportFailedException(ContextEntry.ContextBuilder.entity(getRepository()).build(), "could not execute pull command", ex);
|
||||
} finally {
|
||||
iniConfigurator.removeAuthenticationConfig();
|
||||
throw new ImportFailedException(entity(getRepository()).build(), "could not execute pull command", ex);
|
||||
}
|
||||
|
||||
firePostReceiveRepositoryHookEvent();
|
||||
@@ -88,4 +91,5 @@ public class HgPullCommand extends AbstractHgPushOrPullCommand implements PullCo
|
||||
private void firePostReceiveRepositoryHookEvent() {
|
||||
eventBus.post(eventFactory.createEvent(context, changesetResolver));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,47 +24,59 @@
|
||||
|
||||
package sonia.scm.repository.spi;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.aragost.javahg.Changeset;
|
||||
import com.aragost.javahg.commands.ExecutionException;
|
||||
import com.google.common.base.Strings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.repository.HgRepositoryHandler;
|
||||
import sonia.scm.repository.InternalRepositoryException;
|
||||
import sonia.scm.repository.api.ImportFailedException;
|
||||
import sonia.scm.repository.api.PushResponse;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static com.aragost.javahg.commands.flags.PushCommandFlags.on;
|
||||
import static sonia.scm.ContextEntry.ContextBuilder.entity;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class HgPushCommand extends AbstractHgPushOrPullCommand implements PushCommand {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(HgPushCommand.class);
|
||||
|
||||
public HgPushCommand(HgRepositoryHandler handler, HgCommandContext context) {
|
||||
private final TemporaryConfigFactory configFactory;
|
||||
|
||||
@Inject
|
||||
public HgPushCommand(HgRepositoryHandler handler, HgCommandContext context, TemporaryConfigFactory configFactory) {
|
||||
super(handler, context);
|
||||
this.configFactory = configFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PushResponse push(PushCommandRequest request)
|
||||
throws IOException {
|
||||
@SuppressWarnings("java:S3252") // this is how javahg is used
|
||||
public PushResponse push(PushCommandRequest request) throws IOException {
|
||||
String url = getRemoteUrl(request);
|
||||
|
||||
LOG.debug("push changes from {} to {}", getRepository(), url);
|
||||
|
||||
List<Changeset> result;
|
||||
HgIniConfigurator iniConfigurator = new HgIniConfigurator(getContext());
|
||||
try {
|
||||
if (!Strings.isNullOrEmpty(request.getUsername()) && !Strings.isNullOrEmpty(request.getPassword())) {
|
||||
iniConfigurator.addAuthenticationConfig(request, url);
|
||||
}
|
||||
TemporaryConfigFactory.Builder builder = configFactory.withContext(context);
|
||||
if (!Strings.isNullOrEmpty(request.getUsername()) && !Strings.isNullOrEmpty(request.getPassword())) {
|
||||
builder.withCredentials(url, request.getUsername(), request.getPassword());
|
||||
}
|
||||
|
||||
result = on(open()).execute(url);
|
||||
List<Changeset> result;
|
||||
|
||||
try {
|
||||
result = com.aragost.javahg.commands.PushCommand.on(open()).execute(url);
|
||||
} catch (ExecutionException ex) {
|
||||
throw new InternalRepositoryException(getRepository(), "could not execute push command", ex);
|
||||
} finally {
|
||||
iniConfigurator.removeAuthenticationConfig();
|
||||
throw new ImportFailedException(entity(getRepository()).build(), "could not execute pull command", ex);
|
||||
}
|
||||
|
||||
return new PushResponse(result.size());
|
||||
|
||||
@@ -24,13 +24,9 @@
|
||||
|
||||
package sonia.scm.repository.spi;
|
||||
|
||||
import com.google.common.io.Closeables;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Injector;
|
||||
import sonia.scm.repository.Feature;
|
||||
import sonia.scm.repository.HgConfigResolver;
|
||||
import sonia.scm.repository.HgRepositoryFactory;
|
||||
import sonia.scm.repository.HgRepositoryHandler;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.api.Command;
|
||||
import sonia.scm.repository.api.CommandNotSupportedException;
|
||||
|
||||
@@ -68,28 +64,22 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider {
|
||||
Feature.MODIFICATIONS_BETWEEN_REVISIONS
|
||||
);
|
||||
|
||||
private final HgRepositoryHandler handler;
|
||||
private final Injector commandInjector;
|
||||
private final HgCommandContext context;
|
||||
private final HgLazyChangesetResolver lazyChangesetResolver;
|
||||
private final HgRepositoryHookEventFactory eventFactory;
|
||||
private final ScmEventBus eventBus;
|
||||
|
||||
HgRepositoryServiceProvider(HgRepositoryHandler handler,
|
||||
HgConfigResolver configResolver,
|
||||
HgRepositoryFactory factory,
|
||||
HgRepositoryHookEventFactory eventFactory,
|
||||
ScmEventBus eventBus,
|
||||
Repository repository) {
|
||||
this.handler = handler;
|
||||
this.eventBus = eventBus;
|
||||
this.eventFactory = eventFactory;
|
||||
this.context = new HgCommandContext(configResolver, factory, repository);
|
||||
this.lazyChangesetResolver = new HgLazyChangesetResolver(factory, repository);
|
||||
HgRepositoryServiceProvider(Injector injector, HgCommandContext context) {
|
||||
this.commandInjector = injector.createChildInjector(new AbstractModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(HgCommandContext.class).toInstance(context);
|
||||
}
|
||||
});
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
Closeables.close(context, true);
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -104,7 +94,7 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider {
|
||||
|
||||
@Override
|
||||
public BranchCommand getBranchCommand() {
|
||||
return new HgBranchCommand(context, handler.getWorkingCopyFactory());
|
||||
return commandInjector.getInstance(HgBranchCommand.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -124,7 +114,7 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider {
|
||||
|
||||
@Override
|
||||
public IncomingCommand getIncomingCommand() {
|
||||
return new HgIncomingCommand(context, handler);
|
||||
return commandInjector.getInstance(HgIncomingCommand.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -145,22 +135,22 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider {
|
||||
|
||||
@Override
|
||||
public OutgoingCommand getOutgoingCommand() {
|
||||
return new HgOutgoingCommand(context, handler);
|
||||
return commandInjector.getInstance(HgOutgoingCommand.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PullCommand getPullCommand() {
|
||||
return new HgPullCommand(handler, context, eventBus, lazyChangesetResolver, eventFactory);
|
||||
return commandInjector.getInstance(HgPullCommand.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PushCommand getPushCommand() {
|
||||
return new HgPushCommand(handler, context);
|
||||
return commandInjector.getInstance(HgPushCommand.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModifyCommand getModifyCommand() {
|
||||
return new HgModifyCommand(context, handler.getWorkingCopyFactory());
|
||||
return commandInjector.getInstance(HgModifyCommand.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -180,7 +170,7 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider {
|
||||
|
||||
@Override
|
||||
public TagCommand getTagCommand() {
|
||||
return new HgTagCommand(context, handler.getWorkingCopyFactory());
|
||||
return commandInjector.getInstance(HgTagCommand.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -190,7 +180,7 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider {
|
||||
|
||||
@Override
|
||||
public UnbundleCommand getUnbundleCommand() {
|
||||
return new HgUnbundleCommand(context, lazyChangesetResolver, eventFactory);
|
||||
return commandInjector.getInstance(HgUnbundleCommand.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -25,10 +25,8 @@
|
||||
package sonia.scm.repository.spi;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import com.google.inject.Injector;
|
||||
import sonia.scm.plugin.Extension;
|
||||
import sonia.scm.repository.HgConfigResolver;
|
||||
import sonia.scm.repository.HgRepositoryFactory;
|
||||
import sonia.scm.repository.HgRepositoryHandler;
|
||||
import sonia.scm.repository.Repository;
|
||||
|
||||
@@ -38,34 +36,20 @@ import sonia.scm.repository.Repository;
|
||||
@Extension
|
||||
public class HgRepositoryServiceResolver implements RepositoryServiceResolver {
|
||||
|
||||
private final HgRepositoryHandler handler;
|
||||
private final HgConfigResolver configResolver;
|
||||
private final HgRepositoryFactory factory;
|
||||
private final ScmEventBus eventBus;
|
||||
private final HgRepositoryHookEventFactory eventFactory;
|
||||
private final Injector injector;
|
||||
private final HgCommandContextFactory commandContextFactory;
|
||||
|
||||
@Inject
|
||||
public HgRepositoryServiceResolver(HgRepositoryHandler handler,
|
||||
HgConfigResolver configResolver,
|
||||
HgRepositoryFactory factory,
|
||||
ScmEventBus eventBus,
|
||||
HgRepositoryHookEventFactory eventFactory
|
||||
) {
|
||||
this.handler = handler;
|
||||
this.configResolver = configResolver;
|
||||
this.factory = factory;
|
||||
this.eventBus = eventBus;
|
||||
this.eventFactory = eventFactory;
|
||||
public HgRepositoryServiceResolver(Injector injector, HgCommandContextFactory commandContextFactory) {
|
||||
this.injector = injector;
|
||||
this.commandContextFactory = commandContextFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HgRepositoryServiceProvider resolve(Repository repository) {
|
||||
HgRepositoryServiceProvider provider = null;
|
||||
|
||||
if (HgRepositoryHandler.TYPE_NAME.equalsIgnoreCase(repository.getType())) {
|
||||
provider = new HgRepositoryServiceProvider(handler, configResolver, factory, eventFactory, eventBus, repository);
|
||||
return new HgRepositoryServiceProvider(injector, commandContextFactory.create(repository));
|
||||
}
|
||||
|
||||
return provider;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,21 +25,31 @@
|
||||
package sonia.scm.repository.spi;
|
||||
|
||||
import com.aragost.javahg.Repository;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Strings;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import sonia.scm.repository.HgRepositoryHandler;
|
||||
import sonia.scm.repository.Tag;
|
||||
import sonia.scm.repository.api.TagCreateRequest;
|
||||
import sonia.scm.repository.api.TagDeleteRequest;
|
||||
import sonia.scm.repository.work.WorkingCopy;
|
||||
import sonia.scm.user.User;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static sonia.scm.repository.spi.UserFormatter.getUserStringFor;
|
||||
|
||||
public class HgTagCommand extends AbstractWorkingCopyCommand implements TagCommand {
|
||||
|
||||
public static final String DEFAULT_BRANCH_NAME = "default";
|
||||
|
||||
public HgTagCommand(HgCommandContext context, HgWorkingCopyFactory workingCopyFactory) {
|
||||
@Inject
|
||||
public HgTagCommand(HgCommandContext context, HgRepositoryHandler handler) {
|
||||
this(context, handler.getWorkingCopyFactory());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
HgTagCommand(HgCommandContext context, HgWorkingCopyFactory workingCopyFactory) {
|
||||
super(context, workingCopyFactory);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.repository.RepositoryHookEvent;
|
||||
import sonia.scm.repository.api.UnbundleResponse;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@@ -44,6 +45,7 @@ public class HgUnbundleCommand implements UnbundleCommand {
|
||||
private final HgLazyChangesetResolver changesetResolver;
|
||||
private final HgRepositoryHookEventFactory eventFactory;
|
||||
|
||||
@Inject
|
||||
HgUnbundleCommand(HgCommandContext context,
|
||||
HgLazyChangesetResolver changesetResolver,
|
||||
HgRepositoryHookEventFactory eventFactory
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.repository.spi;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Strings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.io.INIConfiguration;
|
||||
import sonia.scm.io.INIConfigurationReader;
|
||||
import sonia.scm.io.INIConfigurationWriter;
|
||||
import sonia.scm.io.INISection;
|
||||
import sonia.scm.net.GlobalProxyConfiguration;
|
||||
import sonia.scm.repository.HgRepositoryHandler;
|
||||
import sonia.scm.util.Util;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
public class TemporaryConfigFactory {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(TemporaryConfigFactory.class);
|
||||
|
||||
private static final String SECTION_PROXY = "http_proxy";
|
||||
private static final String SECTION_AUTH = "auth";
|
||||
private static final String AUTH_PREFIX = "temporary.";
|
||||
|
||||
private final GlobalProxyConfiguration globalProxyConfiguration;
|
||||
|
||||
@Inject
|
||||
public TemporaryConfigFactory(GlobalProxyConfiguration globalProxyConfiguration) {
|
||||
this.globalProxyConfiguration = globalProxyConfiguration;
|
||||
}
|
||||
|
||||
public Builder withContext(HgCommandContext context) {
|
||||
return new Builder(context);
|
||||
}
|
||||
|
||||
public class Builder {
|
||||
|
||||
private final HgCommandContext context;
|
||||
private String url;
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
private INIConfiguration hgrc;
|
||||
private INISection previousProxyConfiguration;
|
||||
|
||||
private Builder(HgCommandContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public Builder withCredentials(String url, String username, String password) {
|
||||
this.url = url;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("java:S4042") // we know that we delete a file
|
||||
public <T> T call(HgCallable<T> callable) throws IOException {
|
||||
File file = new File(context.getDirectory(), HgRepositoryHandler.PATH_HGRC);
|
||||
boolean exists = file.exists();
|
||||
if (isModificationRequired()) {
|
||||
setupHgrc(file);
|
||||
}
|
||||
try {
|
||||
return callable.call();
|
||||
} finally {
|
||||
if (!exists && file.exists() && !file.delete()) {
|
||||
LOG.error("failed to delete temporary hgrc {}", file);
|
||||
} else if (exists && file.exists()) {
|
||||
cleanUpHgrc(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void write(File file) throws IOException {
|
||||
INIConfigurationWriter writer = new INIConfigurationWriter();
|
||||
writer.write(hgrc, file);
|
||||
}
|
||||
|
||||
private void setupHgrc(File file) throws IOException {
|
||||
if (file.exists()) {
|
||||
INIConfigurationReader reader = new INIConfigurationReader();
|
||||
hgrc = reader.read(file);
|
||||
} else {
|
||||
hgrc = new INIConfiguration();
|
||||
}
|
||||
|
||||
if (isAuthenticationEnabled()) {
|
||||
applyAuthentication(hgrc);
|
||||
}
|
||||
|
||||
if (globalProxyConfiguration.isEnabled()) {
|
||||
applyProxyConfiguration(hgrc);
|
||||
}
|
||||
|
||||
write(file);
|
||||
}
|
||||
|
||||
private void applyProxyConfiguration(INIConfiguration hgrc) {
|
||||
previousProxyConfiguration = hgrc.getSection(SECTION_PROXY);
|
||||
hgrc.removeSection(SECTION_PROXY);
|
||||
INISection proxy = new INISection(SECTION_PROXY);
|
||||
proxy.setParameter("host", globalProxyConfiguration.getHost() + ":" + globalProxyConfiguration.getPort());
|
||||
|
||||
String user = globalProxyConfiguration.getUsername();
|
||||
String passwd = globalProxyConfiguration.getPassword();
|
||||
if (!Strings.isNullOrEmpty(user) && !Strings.isNullOrEmpty(passwd)) {
|
||||
proxy.setParameter("user", user);
|
||||
proxy.setParameter("passwd", passwd);
|
||||
}
|
||||
|
||||
if (Util.isNotEmpty(globalProxyConfiguration.getExcludes())) {
|
||||
proxy.setParameter("no", Joiner.on(',').join(globalProxyConfiguration.getExcludes()));
|
||||
}
|
||||
|
||||
hgrc.addSection(proxy);
|
||||
}
|
||||
|
||||
private void applyAuthentication(INIConfiguration hgrc) {
|
||||
INISection auth = hgrc.getSection(SECTION_AUTH);
|
||||
if (auth == null) {
|
||||
auth = new INISection(SECTION_AUTH);
|
||||
hgrc.addSection(auth);
|
||||
}
|
||||
|
||||
URI uri = URI.create(url);
|
||||
auth.setParameter(AUTH_PREFIX + "prefix", uri.getHost());
|
||||
auth.setParameter(AUTH_PREFIX + "schemes", uri.getScheme());
|
||||
auth.setParameter(AUTH_PREFIX + "username", username);
|
||||
auth.setParameter(AUTH_PREFIX + "password", password);
|
||||
|
||||
}
|
||||
|
||||
private boolean isModificationRequired() {
|
||||
return isAuthenticationEnabled() || globalProxyConfiguration.isEnabled();
|
||||
}
|
||||
|
||||
private boolean isAuthenticationEnabled() {
|
||||
return !Strings.isNullOrEmpty(url)
|
||||
&& !Strings.isNullOrEmpty(username)
|
||||
&& !Strings.isNullOrEmpty(password);
|
||||
}
|
||||
|
||||
private void cleanUpHgrc(File file) throws IOException {
|
||||
INISection auth = hgrc.getSection(SECTION_AUTH);
|
||||
if (isAuthenticationEnabled() && auth != null) {
|
||||
for (String key : auth.getParameterKeys()) {
|
||||
if (key.startsWith(AUTH_PREFIX)) {
|
||||
auth.removeParameter(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (globalProxyConfiguration.isEnabled()) {
|
||||
hgrc.removeSection(SECTION_PROXY);
|
||||
if (previousProxyConfiguration != null) {
|
||||
hgrc.addSection(previousProxyConfiguration);
|
||||
}
|
||||
}
|
||||
|
||||
if (isModificationRequired()) {
|
||||
write(file);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface HgCallable<T> {
|
||||
T call() throws IOException;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user