blob: f996c79672088b21feb89e235e66837bb1cc4d07 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015, 2016 Red Hat Inc. 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
*
* Contributors:
* Red Hat - Initial Contribution
*******************************************************************************/
package org.eclipse.linuxtools.internal.docker.ui.launch;
import static org.eclipse.linuxtools.docker.core.IDockerImageBuildOptions.DOCKER_CONNECTION;
import static org.eclipse.linuxtools.docker.core.IDockerImageBuildOptions.FORCE_RM_INTERMEDIATE_CONTAINERS;
import static org.eclipse.linuxtools.docker.core.IDockerImageBuildOptions.NO_CACHE;
import static org.eclipse.linuxtools.docker.core.IDockerImageBuildOptions.QUIET_BUILD;
import static org.eclipse.linuxtools.docker.core.IDockerImageBuildOptions.REPO_NAME;
import static org.eclipse.linuxtools.docker.core.IDockerImageBuildOptions.RM_INTERMEDIATE_CONTAINERS;
import static org.eclipse.linuxtools.internal.docker.ui.launch.IBuildDockerImageLaunchConfigurationConstants.SOURCE_PATH_LOCATION;
import static org.eclipse.linuxtools.internal.docker.ui.launch.IBuildDockerImageLaunchConfigurationConstants.SOURCE_PATH_WORKSPACE_RELATIVE_LOCATION;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.ui.AbstractLaunchConfigurationTab;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.linuxtools.docker.core.DockerConnectionManager;
import org.eclipse.linuxtools.docker.ui.Activator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.dialogs.ElementTreeSelectionDialog;
import org.eclipse.ui.model.WorkbenchContentProvider;
import org.eclipse.ui.model.WorkbenchLabelProvider;
import org.eclipse.ui.views.navigator.ResourceComparator;
public class BuildDockerImageLaunchConfigurationMainTab
extends AbstractLaunchConfigurationTab {
private final String TAB_NAME = "BuildDockerImageLaunchConfigurationMainTab.name"; //$NON-NLS-1$
private final String CONNECTION_LABEL = "BuildDockerImageLaunchConfigurationMainTab.connection.group.label"; //$NON-NLS-1$
private final String CONNECTION_TOOLTIP = "BuildDockerImageLaunchConfigurationMainTab.connection.group.tooltip"; //$NON-NLS-1$
private final String CONNECTION_MISSING = "BuildDockerImageLaunchConfigurationMainTab.connection.missing"; //$NON-NLS-1$
private final String BUILD_CONTEXT_PATH_LABEL = "BuildDockerImageLaunchConfigurationMainTab.buildContextPath.group.label"; //$NON-NLS-1$
private final String BUILD_CONTEXT_PATH_MISSING = "BuildDockerImageLaunchConfigurationMainTab.buildContextPath.missing"; //$NON-NLS-1$
private final String BUILD_CONTEXT_PATH_MISSING_DOCKERFILE = "BuildDockerImageLaunchConfigurationMainTab.buildContextPath.missingDockerfile"; //$NON-NLS-1$
private final String BROWSE_WORKSPACE = "BuildDockerImageLaunchConfigurationMainTab.buildContextPath.browseworkspace.button.label"; //$NON-NLS-1$
private final String BROWSE_WORKSPACE_DIALOG_TITLE = "BuildDockerImageLaunchConfigurationMainTab.buildContextPath.browseworkspace.dialog.title"; //$NON-NLS-1$
private final String BROWSE_FILESYSTEM = "BuildDockerImageLaunchConfigurationMainTab.buildContextPath.browsefilesystem.button.label"; //$NON-NLS-1$
private final String REPO_NAME_LABEL = "BuildDockerImageLaunchConfigurationMainTab.repoName.label"; //$NON-NLS-1$
private final String REPO_NAME_MISSING = "BuildDockerImageLaunchConfigurationMainTab.repoName.missing"; //$NON-NLS-1$
private final String OPTIONS_LABEL = "BuildDockerImageLaunchConfigurationMainTab.options.group.label"; //$NON-NLS-1$
private final String OPTION_QUIET_LABEL = "BuildDockerImageLaunchConfigurationMainTab.options.quiet.button.label"; //$NON-NLS-1$
private final String OPTION_NOCACHE_LABEL = "BuildDockerImageLaunchConfigurationMainTab.options.noCache.button.label"; //$NON-NLS-1$
private final String OPTION_RM_LABEL = "BuildDockerImageLaunchConfigurationMainTab.options.rm.button.label"; //$NON-NLS-1$
private final String OPTION_FORCERM_LABEL = "BuildDockerImageLaunchConfigurationMainTab.options.forceRM.button.label"; //$NON-NLS-1$
/** the Docker daemon to use for the image build. */
private ComboViewer connectionSelectionComboViewer;
/** the path to the build context . */
private Text buildContextPathText;
/** whether buildContextPath is relative */
private boolean buildContextPathWorkspaceRelative;
/** build option: name and optional tag. */
private Text repoNameText;
/** build option: do not use cache. */
private Button noCacheButton;
/** build option: quiet mode. */
private Button quietBuildButton;
/** build option: remove intermediate after successful build only. */
private Button removeIntermediateContainersButton;
/** build option: always remove intermediate. */
private Button alwaysRemoveIntermediateContainersButton;
@Override
public void createControl(final Composite parent) {
final Composite container = new Composite(parent, SWT.NONE);
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL)
.grab(true, false).applyTo(container);
GridLayoutFactory.fillDefaults().margins(6, 6).applyTo(container);
setControl(container);
// connection selection
final Group connectionGroup = new Group(container, SWT.NONE);
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL)
.grab(true, false).applyTo(connectionGroup);
GridLayoutFactory.fillDefaults().numColumns(2).margins(6, 6)
.applyTo(connectionGroup);
connectionGroup.setText(LaunchMessages.getString(CONNECTION_LABEL));
connectionGroup
.setToolTipText(LaunchMessages.getString(CONNECTION_TOOLTIP));
final Combo connectionSelectionCombo = new Combo(connectionGroup,
SWT.NONE);
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
.grab(true, false).applyTo(connectionSelectionCombo);
this.connectionSelectionComboViewer = new ComboViewer(
connectionSelectionCombo);
this.connectionSelectionComboViewer
.setContentProvider(new ArrayContentProvider());
this.connectionSelectionComboViewer.setInput(
DockerConnectionManager.getInstance().getConnectionNames());
connectionSelectionCombo
.addSelectionListener(new LaunchConfigurationChangeListener());
// build context path
createBuildContextPathGroup(container);
// repository name
createRepoNameGroup(container);
// dockerfile path
// createDockerfilePathGroup(container);
// build options
createBuildOptionsGroup(container);
}
private void createBuildContextPathGroup(final Composite container) {
final Group buildContextPathLocationGroup = new Group(container,
SWT.BORDER);
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL)
.grab(true, false).applyTo(buildContextPathLocationGroup);
GridLayoutFactory.fillDefaults().margins(6, 6).numColumns(3)
.applyTo(buildContextPathLocationGroup);
buildContextPathLocationGroup
.setText(LaunchMessages.getString(BUILD_CONTEXT_PATH_LABEL));
this.buildContextPathText = new Text(
buildContextPathLocationGroup, SWT.BORDER);
this.buildContextPathText
.addModifyListener(new LaunchConfigurationChangeListener());
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
.grab(true, false).span(3, 1)
.applyTo(this.buildContextPathText);
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
.grab(true, false)
.applyTo(new Label(buildContextPathLocationGroup, SWT.NONE));
final Button browseWorkspaceButton = new Button(
buildContextPathLocationGroup, SWT.NONE);
browseWorkspaceButton
.setText(LaunchMessages.getString(BROWSE_WORKSPACE));
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
.grab(false, false).applyTo(browseWorkspaceButton);
browseWorkspaceButton
.addSelectionListener(onBrowseWorkspace(buildContextPathText, IContainer.class));
final Button browseFileSystemButton = new Button(
buildContextPathLocationGroup, SWT.NONE);
browseFileSystemButton
.setText(LaunchMessages.getString(BROWSE_FILESYSTEM));
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
.grab(false, false).applyTo(browseFileSystemButton);
browseFileSystemButton.addSelectionListener(
onBrowseFileSystemForDirectory(this.buildContextPathText));
}
private void createRepoNameGroup(final Composite container) {
final Group repoNameGroup = new Group(container, SWT.NONE);
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL)
.grab(true, false).applyTo(repoNameGroup);
GridLayoutFactory.fillDefaults().margins(6, 6).numColumns(1)
.applyTo(repoNameGroup);
repoNameGroup.setText(LaunchMessages.getString(REPO_NAME_LABEL));
this.repoNameText = new Text(repoNameGroup, SWT.BORDER);
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
.grab(true, false).applyTo(this.repoNameText);
this.repoNameText
.addModifyListener(new LaunchConfigurationChangeListener());
}
private void createBuildOptionsGroup(final Composite container) {
final Group optionsGroup = new Group(container, SWT.NONE);
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL)
.grab(true, false).applyTo(optionsGroup);
GridLayoutFactory.fillDefaults().margins(6, 6).numColumns(2)
.applyTo(optionsGroup);
optionsGroup.setText(LaunchMessages.getString(OPTIONS_LABEL));
this.quietBuildButton = new Button(optionsGroup, SWT.CHECK);
this.quietBuildButton
.setText(LaunchMessages.getString(OPTION_QUIET_LABEL));
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).span(2, 1)
.grab(true, false).applyTo(this.quietBuildButton);
this.quietBuildButton
.addSelectionListener(new LaunchConfigurationChangeListener());
this.noCacheButton = new Button(optionsGroup, SWT.CHECK);
this.noCacheButton
.setText(LaunchMessages.getString(OPTION_NOCACHE_LABEL));
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).span(2, 1)
.grab(true, false).applyTo(this.noCacheButton);
this.noCacheButton
.addSelectionListener(new LaunchConfigurationChangeListener());
this.removeIntermediateContainersButton = new Button(optionsGroup,
SWT.CHECK);
this.removeIntermediateContainersButton
.setText(LaunchMessages.getString(OPTION_RM_LABEL));
this.removeIntermediateContainersButton
.addSelectionListener(new LaunchConfigurationChangeListener());
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).span(2, 1)
.grab(true, false)
.applyTo(this.removeIntermediateContainersButton);
this.alwaysRemoveIntermediateContainersButton = new Button(optionsGroup,
SWT.CHECK);
this.alwaysRemoveIntermediateContainersButton
.setText(LaunchMessages.getString(OPTION_FORCERM_LABEL));
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).span(2, 1)
.grab(true, false)
.applyTo(this.alwaysRemoveIntermediateContainersButton);
this.alwaysRemoveIntermediateContainersButton
.addSelectionListener(onAlwaysRemoveIntermediateContainers());
this.alwaysRemoveIntermediateContainersButton
.addSelectionListener(new LaunchConfigurationChangeListener());
}
private SelectionListener onAlwaysRemoveIntermediateContainers() {
return new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent e) {
toggleRemoveIntermediateContainersButtonState();
}
};
}
/**
* Opens a dialog to browse the workspace
*
* @return
*/
private SelectionListener onBrowseWorkspace(final Text pathText,
final Class<?> expectedType) {
return new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent e) {
final ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(
getShell(), new WorkbenchLabelProvider(),
new WorkbenchContentProvider());
dialog.setInput(ResourcesPlugin.getWorkspace().getRoot());
dialog.setTitle(LaunchMessages
.getString(BROWSE_WORKSPACE_DIALOG_TITLE));
dialog.setComparator(
new ResourceComparator(ResourceComparator.NAME));
dialog.setAllowMultiple(false);
dialog.setValidator(selection -> {
if (selection.length == 1 && expectedType
.isAssignableFrom(selection[0].getClass())) {
return new Status(IStatus.OK, Activator.PLUGIN_ID,
null);
}
return new Status(IStatus.ERROR, Activator.PLUGIN_ID, null);
});
if (dialog.open() == IDialogConstants.OK_ID) {
final IResource selection = (IResource) dialog
.getFirstResult();
pathText.setText(selection.getFullPath().toOSString());
buildContextPathWorkspaceRelative = true;
}
}
};
}
/**
* Opens a dialog to browse the file system and select a directory
*
* @return
*/
private SelectionListener onBrowseFileSystemForDirectory(final Text pathText) {
return new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent e) {
final DirectoryDialog dialog = new DirectoryDialog(getShell());
final String selection = dialog.open();
if (selection != null) {
pathText.setText(selection);
buildContextPathWorkspaceRelative = false;
}
}
};
}
@Override
public void setDefaults(
final ILaunchConfigurationWorkingCopy configuration) {
}
@Override
public void initializeFrom(final ILaunchConfiguration configuration) {
try {
this.connectionSelectionComboViewer
.setSelection(new StructuredSelection(
configuration.getAttribute(DOCKER_CONNECTION, "")));
this.buildContextPathText.setText(
configuration.getAttribute(SOURCE_PATH_LOCATION, ""));
this.buildContextPathWorkspaceRelative = configuration.getAttribute(
SOURCE_PATH_WORKSPACE_RELATIVE_LOCATION, false);
this.repoNameText
.setText(configuration.getAttribute(REPO_NAME, ""));
this.quietBuildButton.setSelection(
configuration.getAttribute(QUIET_BUILD, false));
this.noCacheButton
.setSelection(configuration.getAttribute(NO_CACHE, false));
this.removeIntermediateContainersButton.setSelection(configuration
.getAttribute(RM_INTERMEDIATE_CONTAINERS, false));
this.alwaysRemoveIntermediateContainersButton.setSelection(
configuration.getAttribute(FORCE_RM_INTERMEDIATE_CONTAINERS,
false));
toggleRemoveIntermediateContainersButtonState();
} catch (CoreException e) {
Activator.log(e);
}
}
@Override
public boolean isValid(final ILaunchConfiguration launchConfig) {
try {
// verify the connection
final String dockerConnection = launchConfig
.getAttribute(DOCKER_CONNECTION, ""); // $NON-NLS-1$
// verify the source path
final String sourcePathLocation = launchConfig
.getAttribute(SOURCE_PATH_LOCATION, ""); // $NON-NLS-1$
final boolean sourcePathWorkspaceRelativeLocation = launchConfig.getAttribute(SOURCE_PATH_WORKSPACE_RELATIVE_LOCATION, false);
final IPath sourcePath = BuildDockerImageUtils.getPath(
sourcePathLocation, sourcePathWorkspaceRelativeLocation);
if (dockerConnection.isEmpty() || dockerConnection == null
|| DockerConnectionManager.getInstance()
.findConnection(dockerConnection) == null) {
setErrorMessage(LaunchMessages.getString(CONNECTION_MISSING));
return false;
} else if (sourcePathLocation.isEmpty() || sourcePath == null) {
setErrorMessage(
LaunchMessages.getString(BUILD_CONTEXT_PATH_MISSING));
return false;
} else if (!sourcePath.append("Dockerfile").toFile().exists()) {
setErrorMessage(LaunchMessages.getString(BUILD_CONTEXT_PATH_MISSING_DOCKERFILE));
return false;
} else {
setErrorMessage(null);
}
final String repoName = launchConfig.getAttribute(REPO_NAME, ""); // $NON-NLS-1$
if (repoName.isEmpty()) {
setWarningMessage(LaunchMessages.getString(REPO_NAME_MISSING));
} else {
setWarningMessage(null);
}
} catch (CoreException e) {
Activator.log(e);
}
return super.isValid(launchConfig);
}
@Override
public void performApply(
final ILaunchConfigurationWorkingCopy configuration) {
final IStructuredSelection connectionSelection = (IStructuredSelection) this.connectionSelectionComboViewer
.getSelection();
if (connectionSelection.getFirstElement() != null) {
configuration.setAttribute(DOCKER_CONNECTION,
connectionSelection.getFirstElement().toString());
}
configuration.setAttribute(SOURCE_PATH_LOCATION,
this.buildContextPathText.getText());
configuration.setAttribute(SOURCE_PATH_WORKSPACE_RELATIVE_LOCATION,
this.buildContextPathWorkspaceRelative);
if (!this.repoNameText.getText().isEmpty()) {
configuration.setAttribute(REPO_NAME, this.repoNameText.getText());
}
configuration.setAttribute(QUIET_BUILD,
this.quietBuildButton.getSelection());
configuration.setAttribute(NO_CACHE, this.noCacheButton.getSelection());
configuration.setAttribute(RM_INTERMEDIATE_CONTAINERS,
this.removeIntermediateContainersButton.getSelection());
configuration.setAttribute(FORCE_RM_INTERMEDIATE_CONTAINERS,
this.alwaysRemoveIntermediateContainersButton.getSelection());
}
@Override
public String getName() {
return LaunchMessages.getString(TAB_NAME);
}
/**
* Enables or disables the
* {@link BuildDockerImageLaunchConfigurationMainTab#removeIntermediateContainersButton}
* given the selection of
* {@link BuildDockerImageLaunchConfigurationMainTab#alwaysRemoveIntermediateContainersButton}
*/
private void toggleRemoveIntermediateContainersButtonState() {
if (BuildDockerImageLaunchConfigurationMainTab.this.alwaysRemoveIntermediateContainersButton
.getSelection()) {
BuildDockerImageLaunchConfigurationMainTab.this.removeIntermediateContainersButton
.setEnabled(false);
} else {
BuildDockerImageLaunchConfigurationMainTab.this.removeIntermediateContainersButton
.setEnabled(true);
}
}
private class LaunchConfigurationChangeListener extends SelectionAdapter
implements ModifyListener {
@Override
public void modifyText(final ModifyEvent e) {
updateLaunchConfigurationDialog();
}
@Override
public void widgetSelected(final SelectionEvent e) {
updateLaunchConfigurationDialog();
}
}
}