blob: c48f346dc3dc6c49b0b32205ff603d92770befae [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013, 2016 Robin Stocker <robin@nibor.org> and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.egit.ui.internal.push;
import java.io.IOException;
import java.net.URISyntaxException;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import org.eclipse.egit.core.op.PushOperationResult;
import org.eclipse.egit.core.op.PushOperationSpecification;
import org.eclipse.egit.ui.internal.SecureStoreUtils;
import org.eclipse.egit.ui.internal.UIIcons;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.components.RepositorySelection;
import org.eclipse.egit.ui.internal.credentials.EGitCredentialsProvider;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.URIish;
/**
* A wizard dedicated to pushing a commit.
*/
public class PushBranchWizard extends Wizard {
private final Repository repository;
private final ObjectId commitToPush;
/**
* In case of detached HEAD, reference is null.
*/
private final Ref ref;
private AddRemotePage addRemotePage;
private PushBranchPage pushBranchPage;
private ConfirmationPage confirmationPage;
/**
* @param repository
* the repository the ref belongs to
* @param ref
*/
public PushBranchWizard(final Repository repository, Ref ref) {
this(repository, ref.getObjectId(), ref);
}
/**
* @param repository
* the repository commit belongs to
* @param commitToPush
*/
public PushBranchWizard(final Repository repository, ObjectId commitToPush) {
this(repository, commitToPush, null);
}
private PushBranchWizard(final Repository repository, ObjectId commitToPush, Ref ref) {
this.repository = repository;
this.commitToPush = commitToPush;
this.ref = ref;
assert (this.repository != null);
assert (this.commitToPush != null);
Set<String> remoteNames = repository.getConfig().getSubsections(ConfigConstants.CONFIG_REMOTE_SECTION);
if (remoteNames.isEmpty())
addRemotePage = new AddRemotePage(repository);
pushBranchPage = new PushBranchPage(repository, commitToPush, ref) {
@Override
public void setVisible(boolean visible) {
if (visible && addRemotePage != null) {
setSelectedRemote(addRemotePage.getRemoteName(),
addRemotePage.getSelection().getURI());
}
super.setVisible(visible);
}
};
// Don't show button if we're configuring a remote in the first step
pushBranchPage.setShowNewRemoteButton(addRemotePage == null);
confirmationPage = new ConfirmationPage(repository) {
@Override
public void setVisible(boolean visible) {
setSelection(getRepositorySelection(), getRefSpecs());
AddRemotePage remotePage = getAddRemotePage();
if (remotePage != null)
setCredentials(remotePage.getCredentials());
super.setVisible(visible);
}
};
setDefaultPageImageDescriptor(UIIcons.WIZBAN_PUSH);
}
@Override
public void addPages() {
if (addRemotePage != null)
addPage(addRemotePage);
addPage(pushBranchPage);
addPage(confirmationPage);
}
@Override
public String getWindowTitle() {
if (ref != null)
return MessageFormat.format(UIText.PushBranchWizard_WindowTitle,
Repository.shortenRefName(this.ref.getName()));
else
return UIText.PushCommitHandler_pushCommitTitle;
}
@Override
public boolean canFinish() {
return getContainer().getCurrentPage() == confirmationPage
&& confirmationPage.isPageComplete();
}
@Override
public boolean performFinish() {
try {
AddRemotePage remotePage = getAddRemotePage();
if (remotePage != null) {
storeCredentials(remotePage);
URIish uri = remotePage.getSelection().getURI();
configureNewRemote(uri);
}
if (pushBranchPage.getUpstreamConfig() != null) {
configureUpstream();
}
startPush();
} catch (IOException e) {
confirmationPage.setErrorMessage(e.getMessage());
return false;
} catch (URISyntaxException e) {
confirmationPage.setErrorMessage(e.getMessage());
return false;
}
return true;
}
private AddRemotePage getAddRemotePage() {
if (addRemotePage != null)
return addRemotePage;
else
return pushBranchPage.getAddRemotePage();
}
private RepositorySelection getRepositorySelection() {
AddRemotePage remotePage = getAddRemotePage();
if (remotePage != null)
return remotePage.getSelection();
else
return new RepositorySelection(null,
pushBranchPage.getRemoteConfig());
}
private List<RefSpec> getRefSpecs() {
String src = this.ref != null ? this.ref.getName() : this.commitToPush.getName();
String dst = pushBranchPage.getFullRemoteReference();
RefSpec refSpec = new RefSpec().setSourceDestination(src, dst)
.setForceUpdate(pushBranchPage.isForceUpdateSelected());
return Arrays.asList(refSpec);
}
private void storeCredentials(AddRemotePage remotePage) {
if (remotePage.getStoreInSecureStore()) {
URIish uri = remotePage.getSelection().getURI();
if (uri != null)
SecureStoreUtils.storeCredentials(
remotePage.getCredentials(), uri);
}
}
private void configureNewRemote(URIish uri) throws URISyntaxException,
IOException {
StoredConfig config = repository.getConfig();
String remoteName = getRemoteName();
RemoteConfig remoteConfig = new RemoteConfig(config, remoteName);
remoteConfig.addURI(uri);
RefSpec defaultFetchSpec = new RefSpec().setForceUpdate(true)
.setSourceDestination(Constants.R_HEADS + "*", //$NON-NLS-1$
Constants.R_REMOTES + remoteName + "/*"); //$NON-NLS-1$
remoteConfig.addFetchRefSpec(defaultFetchSpec);
remoteConfig.update(config);
config.save();
}
private void configureUpstream() throws IOException {
if (this.ref == null) {
// Don't configure upstream for detached HEAD
return;
}
String remoteName = getRemoteName();
String fullRemoteBranchName = pushBranchPage.getFullRemoteReference();
String localBranchName = Repository.shortenRefName(this.ref.getName());
StoredConfig config = repository.getConfig();
config.setString(ConfigConstants.CONFIG_BRANCH_SECTION, localBranchName,
ConfigConstants.CONFIG_KEY_REMOTE, remoteName);
config.setString(ConfigConstants.CONFIG_BRANCH_SECTION, localBranchName,
ConfigConstants.CONFIG_KEY_MERGE, fullRemoteBranchName);
BranchRebaseMode rebaseMode = pushBranchPage.getUpstreamConfig();
if (rebaseMode != null) {
config.setEnum(ConfigConstants.CONFIG_BRANCH_SECTION,
localBranchName, ConfigConstants.CONFIG_KEY_REBASE,
rebaseMode);
}
config.save();
}
private void startPush() throws IOException {
PushOperationResult result = confirmationPage.getConfirmedResult();
PushOperationSpecification pushSpec = result
.deriveSpecification(confirmationPage
.isRequireUnchangedSelected());
PushOperationUI pushOperationUI = new PushOperationUI(repository,
pushSpec, false);
pushOperationUI.setCredentialsProvider(new EGitCredentialsProvider());
pushOperationUI.setShowConfigureButton(false);
if (confirmationPage.isShowOnlyIfChangedSelected())
pushOperationUI.setExpectedResult(result);
pushOperationUI.start();
}
private String getRemoteName() {
return pushBranchPage.getRemoteConfig().getName();
}
}