blob: 6eb0b17286da696454181be6075406d3d16e28e1 [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 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.egit.ui.internal.push;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
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.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.core.settings.GitSettings;
import org.eclipse.egit.ui.Activator;
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.dialogs.Dialog;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.RemoteRefUpdate;
import org.eclipse.jgit.transport.Transport;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.PlatformUI;
class ConfirmationPage extends WizardPage {
static Collection<RemoteRefUpdate> copyUpdates(
final Collection<RemoteRefUpdate> refUpdates) throws IOException {
final Collection<RemoteRefUpdate> copy = new ArrayList<>(
refUpdates.size());
for (final RemoteRefUpdate rru : refUpdates)
copy.add(new RemoteRefUpdate(rru, null));
return copy;
}
private final Repository local;
private RepositorySelection displayedRepoSelection;
private List<RefSpec> displayedRefSpecs;
private PushOperationResult confirmedResult;
private PushResultTable resultPanel;
private Button requireUnchangedButton;
private Button showOnlyIfChanged;
private UserPasswordCredentials credentials;
private String helpContext = null;
public ConfirmationPage(final Repository local) {
super(ConfirmationPage.class.getName());
this.local = local;
setTitle(UIText.ConfirmationPage_title);
setDescription(UIText.ConfirmationPage_description);
}
@Override
public void createControl(final Composite parent) {
final Composite panel = new Composite(parent, SWT.NONE);
panel.setLayout(new GridLayout());
resultPanel = new PushResultTable(panel);
final Control tableControl = resultPanel.getControl();
tableControl
.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
requireUnchangedButton = new Button(panel, SWT.CHECK);
requireUnchangedButton
.setText(UIText.ConfirmationPage_requireUnchangedButton);
showOnlyIfChanged = new Button(panel, SWT.CHECK);
showOnlyIfChanged.setText(UIText.ConfirmationPage_showOnlyIfChanged);
Dialog.applyDialogFont(panel);
setControl(panel);
}
public void setSelection(RepositorySelection repositorySelection, List<RefSpec> specSelection){
checkPreviousPagesSelections(repositorySelection, specSelection);
revalidate(repositorySelection, specSelection);
}
public void setCredentials(UserPasswordCredentials credentials) {
this.credentials = credentials;
}
/**
* Set the ID for context sensitive help
*
* @param id
* help context
*/
public void setHelpContext(String id) {
helpContext = id;
}
@Override
public void performHelp() {
PlatformUI.getWorkbench().getHelpSystem().displayHelp(helpContext);
}
boolean isConfirmed() {
return confirmedResult != null;
}
PushOperationResult getConfirmedResult() {
return confirmedResult;
}
boolean isRequireUnchangedSelected() {
return requireUnchangedButton.getSelection();
}
boolean isShowOnlyIfChangedSelected() {
return showOnlyIfChanged.getSelection();
}
private void checkPreviousPagesSelections(RepositorySelection repositorySelection, List<RefSpec> refSpecs) {
if (!repositorySelection.equals(displayedRepoSelection)
|| !refSpecs.equals(displayedRefSpecs)) {
// Allow user to finish by skipping confirmation...
setPageComplete(true);
} else {
// ... but if user doesn't skip confirmation, allow only when no
// critical errors occurred
setPageComplete(confirmedResult != null);
}
}
private void revalidate(RepositorySelection repositorySelection, List<RefSpec> refSpecs) {
// always update this page
resultPanel.setData(local, null);
confirmedResult = null;
displayedRepoSelection = repositorySelection;
displayedRefSpecs = refSpecs;
setErrorMessage(null);
setPageComplete(false);
getControl().getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
revalidateImpl();
}
});
}
private void revalidateImpl() {
if (getControl().isDisposed() || !isCurrentPage())
return;
final List<RefSpec> fetchSpecs;
if (displayedRepoSelection.isConfigSelected())
fetchSpecs = displayedRepoSelection.getConfig().getFetchRefSpecs();
else
fetchSpecs = null;
final PushOperation operation;
try {
final Collection<RemoteRefUpdate> updates = Transport
.findRemoteRefUpdatesFor(local, displayedRefSpecs,
fetchSpecs);
if (updates.isEmpty()) {
// It can happen only when local refs changed in the mean time.
setErrorMessage(UIText.ConfirmationPage_errorRefsChangedNoMatch);
setPageComplete(false);
return;
}
final PushOperationSpecification spec = new PushOperationSpecification();
for (final URIish uri : displayedRepoSelection.getPushURIs())
spec.addURIRefUpdates(uri, copyUpdates(updates));
operation = new PushOperation(local, spec, true,
GitSettings.getRemoteConnectionTimeout());
if (credentials != null)
operation.setCredentialsProvider(new EGitCredentialsProvider(
credentials.getUser(), credentials.getPassword()));
getContainer().run(true, true, new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor)
throws InvocationTargetException, InterruptedException {
operation.run(monitor);
}
});
} catch (final IOException e) {
setErrorMessage(NLS.bind(
UIText.ConfirmationPage_errorCantResolveSpecs, e
.getMessage()));
return;
} catch (final InvocationTargetException e) {
setErrorMessage(NLS.bind(UIText.ConfirmationPage_errorUnexpected, e
.getCause().getMessage()));
return;
} catch (final InterruptedException e) {
setErrorMessage(UIText.ConfirmationPage_errorInterrupted);
setPageComplete(true);
displayedRefSpecs = null;
displayedRepoSelection = null;
return;
}
final PushOperationResult result = operation.getOperationResult();
resultPanel.setData(local, result);
if (result.isSuccessfulConnectionForAnyURI()) {
setPageComplete(true);
confirmedResult = result;
} else {
final String message = NLS.bind(
UIText.ConfirmationPage_cantConnectToAny, result
.getErrorStringForAllURis());
setErrorMessage(message);
ErrorDialog
.openError(getShell(),
UIText.ConfirmationPage_cantConnectToAnyTitle,
null,
new Status(IStatus.ERROR, Activator.getPluginId(),
message));
}
}
}