blob: e9a2025abe4ad59fc37ab42447c38c1463e8c21e [file] [log] [blame]
/*******************************************************************************
* Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
* Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com>
* Copyright (C) 2012, Robin Stocker <robin@nibor.org>
*
* 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.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.egit.core.op.PushOperation;
import org.eclipse.egit.core.op.PushOperationResult;
import org.eclipse.egit.core.op.PushOperationSpecification;
import org.eclipse.egit.core.securestorage.UserPasswordCredentials;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.UIPreferences;
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.RefSpecPage;
import org.eclipse.egit.ui.internal.components.RepositorySelection;
import org.eclipse.egit.ui.internal.components.RepositorySelectionPage;
import org.eclipse.egit.ui.internal.credentials.EGitCredentialsProvider;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.Wizard;
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.RemoteRefUpdate;
import org.eclipse.jgit.transport.Transport;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.osgi.util.NLS;
/**
* Wizard allowing user to specify all needed data to push to another repository
* - including selection of remote repository and refs specifications.
* <p>
* Push operation is performed upon successful completion of this wizard.
*/
public class PushWizard extends Wizard {
private static final String HELP_CONTEXT = "org.eclipse.egit.ui.PushWizard"; //$NON-NLS-1$
private static String getURIsString(final Collection<URIish> uris) {
final StringBuilder sb = new StringBuilder();
boolean first = true;
for (final URIish uri : uris) {
if (first)
first = false;
else
sb.append(", "); //$NON-NLS-1$
sb.append(uri);
}
return sb.toString();
}
private Repository localDb;
private final RepositorySelectionPage repoPage;
private final RefSpecPage refSpecPage;
private ConfirmationPage confirmPage;
/**
* Create push wizard for specified local repository.
*
* @param localDb
* repository to push from.
* @throws URISyntaxException
* when configuration of this repository contains illegal URIs.
*/
public PushWizard(final Repository localDb) throws URISyntaxException {
this.localDb = localDb;
final List<RemoteConfig> remotes = RemoteConfig
.getAllRemoteConfigs(localDb.getConfig());
repoPage = new RepositorySelectionPage(false, remotes, null);
repoPage.setHelpContext(HELP_CONTEXT);
refSpecPage = new RefSpecPage(localDb, true) {
@Override
public void setVisible(boolean visible) {
if (visible) {
setSelection(repoPage.getSelection());
setCredentials(repoPage.getCredentials());
}
super.setVisible(visible);
}
};
refSpecPage.setHelpContext(HELP_CONTEXT);
confirmPage = new ConfirmationPage(localDb) {
@Override
public void setVisible(boolean visible) {
if (visible) {
setSelection(repoPage.getSelection(), refSpecPage
.getRefSpecs());
setCredentials(repoPage.getCredentials());
}
super.setVisible(visible);
}
};
confirmPage.setHelpContext(HELP_CONTEXT);
setDefaultPageImageDescriptor(UIIcons.WIZBAN_PUSH);
setNeedsProgressMonitor(true);
}
@Override
public void addPages() {
addPage(repoPage);
addPage(refSpecPage);
addPage(confirmPage);
}
@Override
public boolean canFinish() {
if (getContainer().getCurrentPage() == repoPage) {
RepositorySelection sel = repoPage.getSelection();
if (sel.isConfigSelected()) {
RemoteConfig config = sel.getConfig();
return !config.getPushURIs().isEmpty()
|| !config.getURIs().isEmpty();
}
}
return super.canFinish();
}
@Override
public boolean performFinish() {
boolean calledFromRepoPage = false;
if (getContainer().getCurrentPage()==repoPage)
calledFromRepoPage = true;
if (repoPage.getSelection().isConfigSelected()
&& refSpecPage.isSaveRequested()) {
saveRefSpecs();
}
if (repoPage.getStoreInSecureStore()) {
if (!SecureStoreUtils.storeCredentials(repoPage
.getCredentials(), repoPage.getSelection().getURI()))
return false;
}
final PushOperation operation = createPushOperation(calledFromRepoPage);
if (operation == null)
return false;
UserPasswordCredentials credentials = repoPage.getCredentials();
if (credentials != null)
operation.setCredentialsProvider(new EGitCredentialsProvider(
credentials.getUser(), credentials.getPassword()));
final PushOperationResult resultToCompare;
if (confirmPage.isShowOnlyIfChangedSelected())
resultToCompare = confirmPage.getConfirmedResult();
else
resultToCompare = null;
final Job job = new PushJob(localDb, operation, resultToCompare,
getDestinationString(repoPage.getSelection()));
job.setUser(true);
job.schedule();
repoPage.saveUriInPrefs();
return true;
}
@Override
public String getWindowTitle() {
final IWizardPage currentPage = getContainer().getCurrentPage();
if (currentPage == repoPage || currentPage == null)
return UIText.PushWizard_windowTitleDefault;
final String destination = getDestinationString(repoPage.getSelection());
return NLS.bind(UIText.PushWizard_windowTitleWithDestination,
destination);
}
private void saveRefSpecs() {
final RemoteConfig rc = repoPage.getSelection().getConfig();
rc.setPushRefSpecs(refSpecPage.getRefSpecs());
final StoredConfig config = localDb.getConfig();
rc.update(config);
try {
config.save();
} catch (final IOException e) {
ErrorDialog.openError(getShell(), UIText.PushWizard_cantSaveTitle,
UIText.PushWizard_cantSaveMessage, new Status(
IStatus.WARNING, Activator.getPluginId(), e
.getMessage(), e));
// Continue, it's not critical.
}
}
private PushOperation createPushOperation(boolean calledFromRepoPage) {
try {
final PushOperationSpecification spec;
final RemoteConfig config = repoPage.getSelection().getConfig();
if (calledFromRepoPage) {
// obtain the push ref specs from the configuration
// use our own list here, as the config returns a non-modifiable
// list
final Collection<RefSpec> pushSpecs = new ArrayList<>();
pushSpecs.addAll(config.getPushRefSpecs());
final Collection<RemoteRefUpdate> updates = Transport
.findRemoteRefUpdatesFor(localDb, pushSpecs,
config.getFetchRefSpecs());
spec = new PushOperationSpecification();
for (final URIish uri : repoPage.getSelection().getPushURIs())
spec.addURIRefUpdates(uri, ConfirmationPage
.copyUpdates(updates));
} else if (confirmPage.isConfirmed()) {
final PushOperationResult confirmedResult = confirmPage
.getConfirmedResult();
spec = confirmedResult.deriveSpecification(confirmPage
.isRequireUnchangedSelected());
} else {
final Collection<RefSpec> fetchSpecs;
if (config != null)
fetchSpecs = config.getFetchRefSpecs();
else
fetchSpecs = null;
final Collection<RemoteRefUpdate> updates = Transport
.findRemoteRefUpdatesFor(localDb, refSpecPage
.getRefSpecs(), fetchSpecs);
if (updates.isEmpty()) {
ErrorDialog.openError(getShell(),
UIText.PushWizard_missingRefsTitle, null,
new Status(IStatus.ERROR, Activator.getPluginId(),
UIText.PushWizard_missingRefsMessage));
return null;
}
spec = new PushOperationSpecification();
for (final URIish uri : repoPage.getSelection().getPushURIs())
spec.addURIRefUpdates(uri, ConfirmationPage
.copyUpdates(updates));
}
int timeout = Activator.getDefault().getPreferenceStore().getInt(
UIPreferences.REMOTE_CONNECTION_TIMEOUT);
return new PushOperation(localDb, spec, false, timeout);
} catch (final IOException e) {
ErrorDialog.openError(getShell(),
UIText.PushWizard_cantPrepareUpdatesTitle,
UIText.PushWizard_cantPrepareUpdatesMessage, new Status(
IStatus.ERROR, Activator.getPluginId(), e
.getMessage(), e));
return null;
}
}
static String getDestinationString(RepositorySelection repoSelection) {
final String destination;
if (repoSelection.isConfigSelected())
destination = repoSelection.getConfigName();
else
destination = repoSelection.getURI(true).toString();
return destination;
}
static class PushJob extends Job {
private final PushOperation operation;
private final PushOperationResult resultToCompare;
private final String destinationString;
private Repository localDb;
public PushJob(final Repository localDb, final PushOperation operation,
final PushOperationResult resultToCompare,
final String destinationString) {
super(NLS.bind(UIText.PushWizard_jobName, getURIsString(operation
.getSpecification().getURIs())));
this.operation = operation;
this.resultToCompare = resultToCompare;
this.destinationString = destinationString;
this.localDb = localDb;
}
@Override
protected IStatus run(final IProgressMonitor monitor) {
try {
operation.run(monitor);
} catch (final InvocationTargetException e) {
return new Status(IStatus.ERROR, Activator.getPluginId(),
UIText.PushWizard_unexpectedError, e.getCause());
}
final PushOperationResult result = operation.getOperationResult();
if (!result.isSuccessfulConnectionForAnyURI()) {
return new Status(IStatus.ERROR, Activator.getPluginId(), NLS
.bind(UIText.PushWizard_cantConnectToAny, result
.getErrorStringForAllURis()));
}
if (resultToCompare == null || !result.equals(resultToCompare)) {
PushResultDialog.show(localDb, result, destinationString, true,
false);
}
return Status.OK_STATUS;
}
}
}