diff options
author | Xavier Coulon | 2015-11-24 11:01:51 +0000 |
---|---|---|
committer | Jeff Johnston | 2015-11-25 18:48:39 +0000 |
commit | 619bd7c341a7da2e138af68182b46a91d2296d0f (patch) | |
tree | fc4f486ff6defd72b4b8410df04f1d8010a19917 | |
parent | 1bae61b27af903aa285055999c21d39a49a38ebb (diff) | |
download | org.eclipse.linuxtools-619bd7c341a7da2e138af68182b46a91d2296d0f.tar.gz org.eclipse.linuxtools-619bd7c341a7da2e138af68182b46a91d2296d0f.tar.xz org.eclipse.linuxtools-619bd7c341a7da2e138af68182b46a91d2296d0f.zip |
Bug 474196 - Add options to Image build launcher
Added options to
- quiet build
- no cache
- remove intermediate containers on successful build
- always remove intermediate containers
- repo/tag
Build configuration name is generated after the image name (repo + tag)
when available, or falls back to default "DockerFile[<projectName>]" pattern.
Moved ImageNameValidator in a separate class to reuse across wizards
Moved pattern to match image name in DockerImageName for reuse accross
classes
Change-Id: I9e14b74b33bfea37aacfbcae10bac2572ac04c55
Signed-off-by: Xavier Coulon <xcoulon@redhat.com>
Reviewed-on: https://git.eclipse.org/r/59464
Tested-by: Hudson CI
Reviewed-by: Jeff Johnston <jjohnstn@redhat.com>
26 files changed, 1291 insertions, 224 deletions
diff --git a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/DockerConnectionManager.java b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/DockerConnectionManager.java index 8b46f1f6c2..99c8bca7a1 100644 --- a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/DockerConnectionManager.java +++ b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/DockerConnectionManager.java @@ -10,6 +10,8 @@ *******************************************************************************/ package org.eclipse.linuxtools.docker.core; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.eclipse.core.runtime.IStatus; @@ -72,6 +74,17 @@ public class DockerConnectionManager { return connections.toArray(new IDockerConnection[connections.size()]); } + /** + * @return an immutable {@link List} of the {@link IDockerConnection} names + */ + public List<String> getConnectionNames() { + final List<String> connectionNames = new ArrayList<>(); + for (IDockerConnection connection : this.connections) { + connectionNames.add(connection.getName()); + } + return Collections.unmodifiableList(connectionNames); + } + public IDockerConnection findConnection(final String name) { if (name != null) { for (IDockerConnection connection : connections) { diff --git a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/IDockerConnection.java b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/IDockerConnection.java index ca6d18d5be..939b615b1c 100644 --- a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/IDockerConnection.java +++ b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/IDockerConnection.java @@ -13,6 +13,7 @@ package org.eclipse.linuxtools.docker.core; import java.io.OutputStream; import java.util.Collections; import java.util.List; +import java.util.Map; import org.eclipse.core.runtime.IPath; import org.eclipse.linuxtools.internal.docker.core.DockerContainerRefreshManager; @@ -199,6 +200,28 @@ public interface IDockerConnection { String createContainer(IDockerContainerConfig c, IDockerHostConfig hc) throws DockerException, InterruptedException; + /** + * Builds an {@link IDockerImage} + * + * @param path + * path to the build context + * @param name + * optional name and tag of the image to build + * @param handler + * progress handler + * @param buildOptions + * build options + * @return the id of the {@link IDockerImage} that was build + * @throws DockerException + * if building image failed + * @throws InterruptedException + * if the thread was interrupted + */ + String buildImage(final IPath path, final String name, + final IDockerProgressHandler handler, + final Map<String, Object> buildOptions) + throws DockerException, InterruptedException; + public String createContainer(final IDockerContainerConfig config, final IDockerHostConfig hc, final String containerName) throws DockerException, InterruptedException; diff --git a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/IDockerContainerListener.java b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/IDockerContainerListener.java index 5b9b89be94..063272708c 100644 --- a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/IDockerContainerListener.java +++ b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/IDockerContainerListener.java @@ -21,9 +21,10 @@ public interface IDockerContainerListener { * * @param connection * - the Docker connection - * @param list - * - the new list of {@link IDockerContainer} + * @param containers + * the new list of containers */ - void listChanged(IDockerConnection connection, List<IDockerContainer> list); + void listChanged(IDockerConnection connection, + List<IDockerContainer> containers); } diff --git a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/IDockerImageBuildOptions.java b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/IDockerImageBuildOptions.java new file mode 100644 index 0000000000..240d0dfaf2 --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/IDockerImageBuildOptions.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2015 Red Hat. + * 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.docker.core; + +/** + * Name of options passed to the Docker daemon to build an {@link IDockerImage} + * + */ +public interface IDockerImageBuildOptions { + + /** name of the connection to use to build the Image. */ + public final static String DOCKER_CONNECTION = "dockerConnection"; //$NON-NLS-1$ + + /** repo and optionally tag of Image to build. */ + public final static String REPO_NAME = "repoName"; //$NON-NLS-1$ + + /** quiet build option. */ + public static final String QUIET_BUILD = "quietBuild"; //$NON-NLS-1$ + + /** no cache option. */ + public static final String NO_CACHE = "noCache"; //$NON-NLS-1$ + + /** remove intermediate containers option on successful build. */ + public static final String RM_INTERMEDIATE_CONTAINERS = "rm"; //$NON-NLS-1$ + + /** always remove intermediate containers option. */ + public static final String FORCE_RM_INTERMEDIATE_CONTAINERS = "forcerm"; //$NON-NLS-1$ + +} diff --git a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/IDockerImageListener.java b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/IDockerImageListener.java index f01bd7951d..1ec64e747b 100644 --- a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/IDockerImageListener.java +++ b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/IDockerImageListener.java @@ -18,11 +18,12 @@ public interface IDockerImageListener { * Called when the list of {@link IDockerImage} for the given * {@link IDockerConnection} changed * - * @param manager - * - the Docker connection + * @param connection + * the {@link IDockerConnection} in which the list of + * {@link IDockerImage} changed * @param images - * - the new list of {@link IDockerImage} + * the new list of {@link IDockerImage} */ - void listChanged(IDockerConnection manager, List<IDockerImage> images); + void listChanged(IDockerConnection connection, List<IDockerImage> images); } diff --git a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/DockerConnection.java b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/DockerConnection.java index a67f905e5e..6212ce1904 100644 --- a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/DockerConnection.java +++ b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/DockerConnection.java @@ -54,6 +54,7 @@ import org.eclipse.linuxtools.docker.core.IDockerContainerInfo; import org.eclipse.linuxtools.docker.core.IDockerContainerListener; import org.eclipse.linuxtools.docker.core.IDockerHostConfig; import org.eclipse.linuxtools.docker.core.IDockerImage; +import org.eclipse.linuxtools.docker.core.IDockerImageBuildOptions; import org.eclipse.linuxtools.docker.core.IDockerImageInfo; import org.eclipse.linuxtools.docker.core.IDockerImageListener; import org.eclipse.linuxtools.docker.core.IDockerImageSearchResult; @@ -853,11 +854,63 @@ public class DockerConnection implements IDockerConnection, Closeable { } } + @Override + public String buildImage(final IPath path, final String name, + final IDockerProgressHandler handler, + final Map<String, Object> buildOptions) + throws DockerException, InterruptedException { + try { + final DockerProgressHandler d = new DockerProgressHandler(handler); + final java.nio.file.Path p = FileSystems.getDefault() + .getPath(path.makeAbsolute().toOSString()); + return client.build(p, name, d, getBuildParameters(buildOptions)); + } catch (com.spotify.docker.client.DockerRequestException e) { + throw new DockerException(e.message()); + } catch (com.spotify.docker.client.DockerException | IOException e) { + DockerException f = new DockerException(e); + throw f; + } + } + + /** + * Converts the given {@link Map} of build options into an array of + * {@link BuildParameter} when the build options are set a value different from the default value. + * + * @param buildOptions + * the build options + * @return an array of relevant {@link BuildParameter} + */ + private BuildParameter[] getBuildParameters( + final Map<String, Object> buildOptions) { + final List<BuildParameter> buildParameters = new ArrayList<>(); + for (Entry<String, Object> entry : buildOptions.entrySet()) { + final Object optionName = entry.getKey(); + final Object optionValue = entry.getValue(); + + if (optionName.equals(IDockerImageBuildOptions.QUIET_BUILD) + && optionValue.equals(true)) { + buildParameters.add(BuildParameter.QUIET); + } else if (optionName.equals(IDockerImageBuildOptions.NO_CACHE) + && optionValue.equals(true)) { + buildParameters.add(BuildParameter.NO_CACHE); + } else if (optionName + .equals(IDockerImageBuildOptions.RM_INTERMEDIATE_CONTAINERS) + && optionValue.equals(false)) { + buildParameters.add(BuildParameter.NO_RM); + } else if (optionName + .equals(IDockerImageBuildOptions.FORCE_RM_INTERMEDIATE_CONTAINERS) + && optionValue.equals(true)) { + buildParameters.add(BuildParameter.FORCE_RM); + } + } + return buildParameters.toArray(new BuildParameter[0]); + } + public void save() { // Currently we have to save all clouds instead of just this one DockerConnectionManager.getInstance().saveConnections(); } - + @Override @Deprecated public String createContainer(IDockerContainerConfig c) diff --git a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/DockerImage.java b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/DockerImage.java index a29a124d1d..47a9233135 100644 --- a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/DockerImage.java +++ b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/DockerImage.java @@ -17,17 +17,31 @@ import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.regex.Pattern; import org.eclipse.linuxtools.docker.core.IDockerImage; public class DockerImage implements IDockerImage { + private static final String REGISTRY_HOST = "[a-zA-Z0-9]+([\\._-][a-zA-Z0-9]+)*"; //$NON-NLS-1$ + private static final String REGISTRY_PORT = "[0-9]+"; //$NON-NLS-1$ + private static final String REPOSITORY = "[a-z0-9]+([\\._-][a-z0-9]+)*"; //$NON-NLS-1$ + private static final String NAME = "[a-z0-9]+([\\._-][a-z0-9]+)*"; //$NON-NLS-1$ + private static final String TAG = "[a-zA-Z0-9]+([\\._-][a-zA-Z0-9]+)*"; //$NON-NLS-1$ + + /** the image name pattern. */ + public static final Pattern imageNamePattern = Pattern.compile("(" //$NON-NLS-1$ + + REGISTRY_HOST + "\\:" + REGISTRY_PORT + "/)?" //$NON-NLS-1$ //$NON-NLS-2$ + + "((?<repository>" + REPOSITORY + ")/)?" //$NON-NLS-1$ //$NON-NLS-2$ + + "(?<name>" + NAME + ")" //$NON-NLS-1$ //$NON-NLS-2$ + + "(\\:(?<tag>" + TAG + "))?"); //$NON-NLS-1$ //$NON-NLS-2$ + // SimpleDateFormat is not thread-safe, so give one to each thread private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){ @Override protected SimpleDateFormat initialValue() { - return new SimpleDateFormat("yyyy-MM-dd"); + return new SimpleDateFormat("yyyy-MM-dd"); //$NON-NLS-1$ } }; diff --git a/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/validators/BuildDockerImageUtilsTest.java b/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/validators/BuildDockerImageUtilsTest.java new file mode 100644 index 0000000000..0968467c72 --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/validators/BuildDockerImageUtilsTest.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2015 Red Hat. + * 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.validators; + +import org.eclipse.linuxtools.internal.docker.ui.launch.BuildDockerImageUtils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +/** + * Testing the {@link BuildDockerImageUtils}. + */ +@RunWith(Parameterized.class) +public class BuildDockerImageUtilsTest { + + private static Object[] match(final String imageName, final String expectedRepository, final String expectedName, final String expectedTag) { + return new Object[] { imageName, expectedRepository, expectedName, expectedTag }; + } + + @Parameters(name = "{0} -> {1}/{2}:{3}") + public static Object[][] data() { + return new Object[][] { match("", null, null, null), + match("£", null, null, null), // because £ is an invalid character + match("wildfly", null, "wildfly", null), + match("jboss/", null, null, null), + match("jboss/wildfly", "jboss", "wildfly", null), + match("jboss/wildfly:", null , null, null), // because ':' causes invalid value + match("jboss/wildfly:latest", "jboss", "wildfly", "latest"), + match("localhost/wildfly/", null, null, null), // because registry is missing port number + match("localhost/jboss/wildfly", null, null, null), // because registry is missing port number + match("localhost/jboss/wildfly:", null, null, null), // because registry is missing port number + match("localhost/jboss/wildfly:latest", null, null, null), // because registry is missing port number + match("localhost/jboss/wildfly:9", null, null, null), // because registry is missing port number + match("localhost/jboss/wildfly:9.", null, null, null), // because registry is missing port number + match("localhost/jboss/wildfly:9.0.1.Final", null, null, null), // because registry is missing port number + match("localhost:", null, null, null), // because trailing ':' causes invalid value + match("localhost:5000", null, "localhost", "5000"), // bc it matches the REPO:TAG pattern. + match("localhost:5000/", null, null, null), // because trailing '/' causes invalid value + match("localhost:5000/jboss/wildfly", "jboss", "wildfly", null), + match("localhost:5000/jboss/wildfly/", null, null, null), // because trailing '/' causes invalid value + match("localhost:5000/jboss/wildfly", "jboss", "wildfly", null), + match("localhost:5000/jboss/wildfly:", null, null, null), // because ':' causes invalid value + match("localhost:5000/jboss/wildfly:latest", "jboss", "wildfly", "latest"), + }; + } + + @Parameter(value = 0) + public String imageName; + @Parameter(value = 1) + public String expectedRepository; + @Parameter(value = 2) + public String expectedName; + @Parameter(value = 3) + public String expectedTag; + + @Test + public void verifyRepository() { + // when + final String actualRepository = BuildDockerImageUtils.getRepository(imageName); + // then + Assert.assertEquals(expectedRepository, actualRepository); + } + + @Test + public void verifyName() { + // when + final String actualName = BuildDockerImageUtils.getName(imageName); + // then + Assert.assertEquals(expectedName, actualName); + } + + @Test + public void verifyTag() { + // when + final String actualTagName = BuildDockerImageUtils.getTag(imageName); + // then + Assert.assertEquals(expectedTag, actualTagName); + } + +} diff --git a/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/validators/package-info.java b/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/validators/package-info.java new file mode 100644 index 0000000000..319edc510a --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/validators/package-info.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2015 Red Hat. + * 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.validators;
\ No newline at end of file diff --git a/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImagePullPatternTest.java b/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImagePullPatternTest.java index dc6bff7e9d..2fe4e05910 100644 --- a/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImagePullPatternTest.java +++ b/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImagePullPatternTest.java @@ -11,6 +11,7 @@ package org.eclipse.linuxtools.internal.docker.ui.wizards; import org.eclipse.core.runtime.IStatus; +import org.eclipse.linuxtools.internal.docker.ui.validators.ImageNameValidator; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -19,13 +20,12 @@ import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) -public class ImagePullPatternTest { +public class ImagePullPatternTest { private static Object[] match(final String imageName, final int expectedSeverity) { return new Object[]{imageName, expectedSeverity}; } - @Parameters(name="{0} -> {1}") public static Object[][] data() { return new Object[][] { @@ -37,21 +37,21 @@ public class ImagePullPatternTest { match("jboss/wildfly:", IStatus.WARNING), match("jboss/wildfly:latest", IStatus.OK), match("localhost/wildfly/", IStatus.WARNING), - match("localhost/wildfly/jboss", IStatus.WARNING), - match("localhost/wildfly/jboss:", IStatus.WARNING), - match("localhost/wildfly/jboss:latest", IStatus.OK), - match("localhost/wildfly/jboss:9", IStatus.OK), - match("localhost/wildfly/jboss:9.", IStatus.WARNING), - match("localhost/wildfly/jboss:9.0.1.", IStatus.WARNING), - match("localhost/wildfly/jboss:9.0.1.Final", IStatus.OK), + match("localhost/jboss/wildfly", IStatus.WARNING), + match("localhost/jboss/wildfly:", IStatus.WARNING), + match("localhost/jboss/wildfly:latest", IStatus.WARNING), + match("localhost/jboss/wildfly:9", IStatus.WARNING), + match("localhost/jboss/wildfly:9.", IStatus.WARNING), + match("localhost/jboss/wildfly:9.0.1.", IStatus.WARNING), + match("localhost/jboss/wildfly:9.0.1.Final", IStatus.WARNING), match("localhost:", IStatus.WARNING), match("localhost:5000", IStatus.OK), // bc it matches the REPO:TAG pattern. match("localhost:5000/", IStatus.WARNING), - match("localhost:5000/wildfly", IStatus.WARNING), - match("localhost:5000/wildfly/", IStatus.WARNING), - match("localhost:5000/wildfly/jboss", IStatus.WARNING), - match("localhost:5000/wildfly/jboss:", IStatus.WARNING), - match("localhost:5000/wildfly/jboss:latest", IStatus.OK), + match("localhost:5000/jboss/wildfly", IStatus.WARNING), + match("localhost:5000/jboss/wildfly/", IStatus.WARNING), + match("localhost:5000/jboss/wildfly", IStatus.WARNING), + match("localhost:5000/jboss/wildfly:", IStatus.WARNING), + match("localhost:5000/jboss/wildfly:latest", IStatus.OK), }; } @@ -63,7 +63,7 @@ public class ImagePullPatternTest { @Test public void verifyData() { - final IStatus status = new ImagePullPage.ImageNameValidator().validate(imageName); + final IStatus status = new ImageNameValidator().validate(imageName); // then Assert.assertEquals(expectedSeverity, status.getSeverity()); } diff --git a/containers/org.eclipse.linuxtools.docker.ui/META-INF/MANIFEST.MF b/containers/org.eclipse.linuxtools.docker.ui/META-INF/MANIFEST.MF index 9150e20569..0941576aae 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/META-INF/MANIFEST.MF +++ b/containers/org.eclipse.linuxtools.docker.ui/META-INF/MANIFEST.MF @@ -32,4 +32,6 @@ Export-Package: org.eclipse.linuxtools.docker.ui, org.eclipse.linuxtools.internal.docker.ui.commands;x-friends:="org.eclipse.linuxtools.docker.ui.tests", org.eclipse.linuxtools.internal.docker.ui.preferences, org.eclipse.linuxtools.internal.docker.ui.views;x-friends:="org.eclipse.linuxtools.docker.ui.tests", + org.eclipse.linuxtools.internal.docker.ui.launch;x-friends:="org.eclipse.linuxtools.docker.ui.tests", + org.eclipse.linuxtools.internal.docker.ui.validators;x-friends:="org.eclipse.linuxtools.docker.ui.tests", org.eclipse.linuxtools.internal.docker.ui.wizards;x-friends:="org.eclipse.linuxtools.docker.ui.tests" diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/docker/ui/launch/ContainerLauncher.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/docker/ui/launch/ContainerLauncher.java index 9632dced0e..0ca6f287d3 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/docker/ui/launch/ContainerLauncher.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/docker/ui/launch/ContainerLauncher.java @@ -231,7 +231,7 @@ public class ContainerLauncher { String containerId = null; try { containerId = ((DockerConnection) connection) - .createContainer(config, hostConfig); + .createContainer(config, hostConfig, null); OutputStream stream = null; RunConsole oldConsole = getConsole(); final RunConsole rc = RunConsole.findConsole(containerId, diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/jobs/BuildDockerImageJob.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/jobs/BuildDockerImageJob.java index b778f73a2f..86e672e234 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/jobs/BuildDockerImageJob.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/jobs/BuildDockerImageJob.java @@ -16,6 +16,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.util.Map; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; @@ -31,6 +32,7 @@ import org.eclipse.linuxtools.docker.core.IDockerProgressHandler; import org.eclipse.linuxtools.docker.core.IDockerProgressMessage; import org.eclipse.linuxtools.docker.ui.Activator; import org.eclipse.linuxtools.internal.docker.ui.BuildConsole; +import org.eclipse.linuxtools.internal.docker.ui.launch.IBuildDockerImageLaunchConfigurationConstants; import org.eclipse.swt.widgets.Display; /** @@ -51,6 +53,12 @@ public class BuildDockerImageJob extends Job implements IDockerProgressHandler { /** The path to the source code. */ private final IPath path; + /** the build options. */ + private final Map<String, Object> buildOptions; + + /** the optional repoName (i.e., repo[tag]) for the image to build */ + private final String repoName; + /** The number of steps to build the image. */ private final int numberOfBuildOperations; @@ -64,21 +72,30 @@ public class BuildDockerImageJob extends Job implements IDockerProgressHandler { * Constructor * * @param connection - * the Docker connection to use (ie, on which Docker engine to + * the Docker connection to use (i.e., on which Docker engine to * build the image) * @param path * the path to the source code + * @param repoName + * the optional repoName (i.e., repo[tag]) for the image to build + * @param buildOptions + * build options * @throws IOException + * @see {@link IBuildDockerImageLaunchConfigurationConstants} for build + * options. */ public BuildDockerImageJob(final IDockerConnection connection, - final IPath path) throws DockerException { + final IPath path, final String repoName, + final Map<String, Object> buildOptions) + throws DockerException { super(JobMessages.getString(BUILD_IMAGE_JOB_TITLE)); this.connection = connection; this.path = path; + this.repoName = repoName; + this.buildOptions = buildOptions; this.console = BuildConsole.findConsole(); this.numberOfBuildOperations = countLines( path.addTrailingSeparator().append("Dockerfile").toOSString()); //$NON-NLS-1$ - } @Override @@ -94,13 +111,21 @@ public class BuildDockerImageJob extends Job implements IDockerProgressHandler { this.progressMonitor.beginTask( JobMessages.getString(BUILD_IMAGE_JOB_TITLE), numberOfBuildOperations + 1); - // Give the Image a default name so it can be tagged later. - // Otherwise, the Image will be treated as an intermediate Image - // by the view filters and Tag Image action will be disabled. - // Use the current time in milliseconds to make it unique. - String name = "dockerfile:" //$NON-NLS-1$ - + Long.toHexString(System.currentTimeMillis()); - connection.buildImage(path, name, this); + if (repoName == null) { + // Give the Image a default name so it can be tagged later. + // Otherwise, the Image will be treated as an intermediate + // Image + // by the view filters and Tag Image action will be + // disabled. + // Use the current time in milliseconds to make it unique. + final String name = "dockerfile:" //$NON-NLS-1$ + + Long.toHexString(System.currentTimeMillis()); + connection.buildImage(this.path, name, this, + this.buildOptions); + } else { + connection.buildImage(this.path, this.repoName, this, + this.buildOptions); + } connection.getImages(true); } } catch (DockerException | InterruptedException e) { @@ -162,7 +187,7 @@ public class BuildDockerImageJob extends Job implements IDockerProgressHandler { * statements to execute (ignoring comments and empty lines). * * @param fileName - * the full name of the Docker file to read + * the full repoName of the Docker file to read * @return the number of instructions. * @throws DockerException * @throws IOException diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/BuildDockerImageLaunchConfigurationDelegate.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/BuildDockerImageLaunchConfigurationDelegate.java index bb60539517..387051cb4e 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/BuildDockerImageLaunchConfigurationDelegate.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/BuildDockerImageLaunchConfigurationDelegate.java @@ -11,16 +11,22 @@ package org.eclipse.linuxtools.internal.docker.ui.launch; -import static org.eclipse.linuxtools.internal.docker.ui.launch.IBuildDockerImageLaunchConfigurationConstants.DOCKER_CONNECTION; +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.ResourcesPlugin; +import java.util.HashMap; +import java.util.Map; + import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.debug.core.ILaunch; @@ -44,18 +50,31 @@ public class BuildDockerImageLaunchConfigurationDelegate private static final String MISSING_CONNECTION_ERROR_MSG = "MissingConnectionError.msg"; //$NON-NLS-1$ @Override - public void launch(ILaunchConfiguration configuration, String mode, - ILaunch launch, IProgressMonitor monitor) throws CoreException { + public void launch(final ILaunchConfiguration configuration, + final String mode, final ILaunch launch, + final IProgressMonitor monitor) throws CoreException { final String sourcePathLocation = configuration .getAttribute(SOURCE_PATH_LOCATION, (String) null); final boolean sourcePathWorkspaceRelativeLocation = configuration - .getAttribute(SOURCE_PATH_WORKSPACE_RELATIVE_LOCATION, false); - final IPath sourcePath = getPath(sourcePathLocation, + .getAttribute(SOURCE_PATH_WORKSPACE_RELATIVE_LOCATION, + false); + final IPath sourcePath = BuildDockerImageUtils.getPath( + sourcePathLocation, sourcePathWorkspaceRelativeLocation); final String connectionName = configuration .getAttribute(DOCKER_CONNECTION, (String) null); + final String repoName = configuration.getAttribute(REPO_NAME, + (String) null); final DockerConnection connection = (DockerConnection) getDockerConnection( connectionName); + final Map<String, Object> buildOptions = new HashMap<>(); + buildOptions.put(QUIET_BUILD, + configuration.getAttribute(QUIET_BUILD, false)); + buildOptions.put(NO_CACHE, configuration.getAttribute(NO_CACHE, false)); + buildOptions.put(RM_INTERMEDIATE_CONTAINERS, configuration + .getAttribute(RM_INTERMEDIATE_CONTAINERS, true)); + buildOptions.put(FORCE_RM_INTERMEDIATE_CONTAINERS, configuration + .getAttribute(FORCE_RM_INTERMEDIATE_CONTAINERS, false)); if (connection == null) { Activator .log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, @@ -64,24 +83,21 @@ public class BuildDockerImageLaunchConfigurationDelegate connectionName))); } try { - final Job buildImageJob = new BuildDockerImageJob(connection, - sourcePath); - buildImageJob.schedule(); + if (connection != null && sourcePath != null) { + final Job buildImageJob = new BuildDockerImageJob(connection, + sourcePath, repoName, buildOptions); + buildImageJob.schedule(); + } else { + Activator.log(new Status(IStatus.WARNING, Activator.PLUGIN_ID, + LaunchMessages.getString( + "BuildDockerImageLaunchConfiguration.error.incomplete"))); //$NON-NLS-1$ + } } catch (DockerException e) { Activator.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e)); } } - private IPath getPath(final String sourcePathLocation, - final boolean sourcePathWorkspaceRelativeLocation) { - if (sourcePathWorkspaceRelativeLocation) { - return ResourcesPlugin.getWorkspace().getRoot() - .findMember(new Path(sourcePathLocation)).getLocation(); - } - return new Path(sourcePathLocation); - } - /** * Finds the {@link IDockerConnection} from the given name * diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/BuildDockerImageLaunchConfigurationMainTab.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/BuildDockerImageLaunchConfigurationMainTab.java index 92a6077150..df658e32fe 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/BuildDockerImageLaunchConfigurationMainTab.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/BuildDockerImageLaunchConfigurationMainTab.java @@ -11,17 +11,23 @@ package org.eclipse.linuxtools.internal.docker.ui.launch; -import static org.eclipse.linuxtools.internal.docker.ui.launch.IBuildDockerImageLaunchConfigurationConstants.DOCKER_CONNECTION; +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 java.util.ArrayList; -import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; 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; @@ -35,7 +41,6 @@ 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.core.IDockerConnection; import org.eclipse.linuxtools.docker.ui.Activator; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; @@ -47,6 +52,7 @@ 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.FileDialog; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; @@ -60,16 +66,40 @@ public class BuildDockerImageLaunchConfigurationMainTab extends AbstractLaunchConfigurationTab { private final String TAB_NAME = "BuildDockerImageLaunchConfigurationMainTab.name"; //$NON-NLS-1$ - private final String SOURCE_PATH_LOCATION_LABEL = "BuildDockerImageLaunchConfigurationMainTab.sourcePathLocation.group.label"; //$NON-NLS-1$ private final String CONNECTION_LABEL = "BuildDockerImageLaunchConfigurationMainTab.connection.group.label"; //$NON-NLS-1$ - private final String BROWSE_WORKSPACE = "BuildDockerImageLaunchConfigurationMainTab.browseworkspace.button.label"; //$NON-NLS-1$ - private final String BROWSE_WORKSPACE_DIALOG_TITLE = "BuildDockerImageLaunchConfigurationMainTab.browseworkspace.dialog.title"; //$NON-NLS-1$ - private final String BROWSE_WORKSPACE_DIALOG_MESSAGE = "BuildDockerImageLaunchConfigurationMainTab.browseworkspace.dialog.message"; //$NON-NLS-1$ - private final String BROWSE_FILESYSTEM = "BuildDockerImageLaunchConfigurationMainTab.browsefilesystem.button.label"; //$NON-NLS-1$ + private final String CONNECTION_TOOLTIP = "BuildDockerImageLaunchConfigurationMainTab.connection.group.tooltip"; //$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 DOCKERFILE_PATH_LABEL = "BuildDockerImageLaunchConfigurationMainTab.dockerfilePath.group.label"; //$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$ - private Text sourcePathLocationText; - private boolean sourcePathWorkspaceRelativeLocation; + /** the Docker daemon to use for the image build. */ private ComboViewer connectionSelectionComboViewer; + /** the path to the build context . */ + private Text buildContextPathText; + private AtomicBoolean buildContextPathWorkspaceRelative; + /** the path to the Dockerfile. */ + private Text dockerFilePathText; + private AtomicBoolean dockerFilePathWorkspaceRelative; + /** 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) { @@ -79,65 +109,185 @@ public class BuildDockerImageLaunchConfigurationMainTab GridLayoutFactory.fillDefaults().margins(6, 6).applyTo(container); setControl(container); - // source path location - final Group sourcePathLocationGroup = new Group(container, SWT.BORDER); + // connection selection + final Group connectionGroup = new Group(container, SWT.BORDER); + 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(sourcePathLocationGroup); + .grab(true, false).applyTo(buildContextPathLocationGroup); GridLayoutFactory.fillDefaults().margins(6, 6).numColumns(3) - .applyTo(sourcePathLocationGroup); - sourcePathLocationGroup - .setText(LaunchMessages.getString(SOURCE_PATH_LOCATION_LABEL)); - sourcePathLocationText = new Text(sourcePathLocationGroup, SWT.BORDER); - sourcePathLocationText + .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(sourcePathLocationText); + .grab(true, false).span(3, 1) + .applyTo(this.buildContextPathText); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .grab(true, false) - .applyTo(new Label(sourcePathLocationGroup, SWT.NONE)); + .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, + buildContextPathWorkspaceRelative, 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, + this.buildContextPathWorkspaceRelative)); + } - final Button browseWorkspaceButton = new Button(sourcePathLocationGroup, - SWT.NONE); + @SuppressWarnings("unused") + private void createDockerfilePathGroup(final Composite container) { + final Group dockerFilePathLocationGroup = new Group(container, + SWT.BORDER); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL) + .grab(true, false).applyTo(dockerFilePathLocationGroup); + GridLayoutFactory.fillDefaults().margins(6, 6).numColumns(3) + .applyTo(dockerFilePathLocationGroup); + dockerFilePathLocationGroup + .setText(LaunchMessages.getString(DOCKERFILE_PATH_LABEL)); + this.dockerFilePathText = new Text( + dockerFilePathLocationGroup, SWT.BORDER); + this.dockerFilePathText + .addModifyListener(new LaunchConfigurationChangeListener()); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(true, false).span(3, 1).applyTo(this.dockerFilePathText); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(true, false) + .applyTo(new Label(dockerFilePathLocationGroup, SWT.NONE)); + final Button browseWorkspaceButton = new Button( + dockerFilePathLocationGroup, SWT.NONE); browseWorkspaceButton .setText(LaunchMessages.getString(BROWSE_WORKSPACE)); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .grab(false, false).applyTo(browseWorkspaceButton); - browseWorkspaceButton.addSelectionListener(onBrowseWorkspace()); + browseWorkspaceButton + .addSelectionListener(onBrowseWorkspace(dockerFilePathText, + dockerFilePathWorkspaceRelative, IFile.class)); final Button browseFileSystemButton = new Button( - sourcePathLocationGroup, - SWT.NONE); + dockerFilePathLocationGroup, SWT.NONE); browseFileSystemButton .setText(LaunchMessages.getString(BROWSE_FILESYSTEM)); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .grab(false, false).applyTo(browseFileSystemButton); - browseFileSystemButton.addSelectionListener(onBrowseFileSystem()); + browseFileSystemButton.addSelectionListener(onBrowseFileSystemForFile( + this.dockerFilePathText, this.dockerFilePathWorkspaceRelative)); + } - // connection - final Group connectionGroup = new Group(container, SWT.BORDER); + private void createRepoNameGroup(final Composite container) { + final Group repoNameGroup = new Group(container, SWT.BORDER); 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)); - final Combo connectionSelectionCombo = new Combo(connectionGroup, - SWT.NONE); + .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(connectionSelectionCombo); - connectionSelectionComboViewer = new ComboViewer( - connectionSelectionCombo); - connectionSelectionComboViewer - .setContentProvider(new ArrayContentProvider()); - connectionSelectionComboViewer.setInput(getConnectionNames()); - connectionSelectionCombo.addSelectionListener(new LaunchConfigurationChangeListener()); + .grab(true, false).applyTo(this.repoNameText); + this.repoNameText + .addModifyListener(new LaunchConfigurationChangeListener()); } - private List<String> getConnectionNames() { - final List<String> connectionNames = new ArrayList<>(); - for (IDockerConnection connection : DockerConnectionManager - .getInstance().getConnections()) { - connectionNames.add(connection.getName()); - } - return connectionNames; + private void createBuildOptionsGroup(final Composite container) { + final Group optionsGroup = new Group(container, SWT.BORDER); + 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(); + } + + }; } /** @@ -145,7 +295,9 @@ public class BuildDockerImageLaunchConfigurationMainTab * * @return */ - private SelectionListener onBrowseWorkspace() { + private SelectionListener onBrowseWorkspace(final Text pathText, + final AtomicBoolean workspaceRelativePath, + final Class<?> expectedType) { return new SelectionAdapter() { @Override @@ -156,8 +308,6 @@ public class BuildDockerImageLaunchConfigurationMainTab dialog.setInput(ResourcesPlugin.getWorkspace().getRoot()); dialog.setTitle(LaunchMessages .getString(BROWSE_WORKSPACE_DIALOG_TITLE)); - dialog.setMessage(LaunchMessages - .getString(BROWSE_WORKSPACE_DIALOG_MESSAGE)); dialog.setComparator( new ResourceComparator(ResourceComparator.NAME)); dialog.setAllowMultiple(false); @@ -165,8 +315,8 @@ public class BuildDockerImageLaunchConfigurationMainTab // only accept a single file as the valid selection @Override public IStatus validate(Object[] selection) { - if (selection.length == 1 - && selection[0] instanceof IContainer) { + if (selection.length == 1 && expectedType + .isAssignableFrom(selection[0].getClass())) { return new Status(IStatus.OK, Activator.PLUGIN_ID, null); } @@ -177,20 +327,20 @@ public class BuildDockerImageLaunchConfigurationMainTab if (dialog.open() == IDialogConstants.OK_ID) { final IResource selection = (IResource) dialog .getFirstResult(); - sourcePathLocationText - .setText(selection.getFullPath().toOSString()); - sourcePathWorkspaceRelativeLocation = true; + pathText.setText(selection.getFullPath().toOSString()); + workspaceRelativePath.set(true); } } }; } /** - * Opens a dialog to browse the file system + * Opens a dialog to browse the file system and select a directory * * @return */ - private SelectionListener onBrowseFileSystem() { + private SelectionListener onBrowseFileSystemForDirectory(final Text pathText, + final AtomicBoolean workspaceRelativePath) { return new SelectionAdapter() { @Override @@ -198,8 +348,29 @@ public class BuildDockerImageLaunchConfigurationMainTab final DirectoryDialog dialog = new DirectoryDialog(getShell()); final String selection = dialog.open(); if (selection != null) { - sourcePathLocationText.setText(selection); - sourcePathWorkspaceRelativeLocation = false; + pathText.setText(selection); + workspaceRelativePath.set(false); + } + } + }; + } + + /** + * Opens a dialog to browse the file system and select a file + * + * @return + */ + private SelectionListener onBrowseFileSystemForFile(final Text pathText, + final AtomicBoolean workspaceRelativePath) { + return new SelectionAdapter() { + + @Override + public void widgetSelected(final SelectionEvent e) { + final FileDialog dialog = new FileDialog(getShell()); + final String selection = dialog.open(); + if (selection != null) { + pathText.setText(selection); + workspaceRelativePath.set(false); } } }; @@ -214,23 +385,58 @@ public class BuildDockerImageLaunchConfigurationMainTab @Override public void initializeFrom(final ILaunchConfiguration configuration) { try { - this.sourcePathLocationText.setText( - configuration.getAttribute(SOURCE_PATH_LOCATION, "")); - this.sourcePathWorkspaceRelativeLocation = configuration - .getAttribute(SOURCE_PATH_WORKSPACE_RELATIVE_LOCATION, false); this.connectionSelectionComboViewer .setSelection(new StructuredSelection( configuration.getAttribute(DOCKER_CONNECTION, ""))); + this.buildContextPathText.setText( + configuration.getAttribute(SOURCE_PATH_LOCATION, "")); + this.buildContextPathWorkspaceRelative = new AtomicBoolean( + configuration.getAttribute( + SOURCE_PATH_WORKSPACE_RELATIVE_LOCATION, false)); + // this.dockerFilePathText.setText( + // configuration.getAttribute(DOCKERFILE_PATH, "Dockerfile")); + // this.dockerFilePathWorkspaceRelative = new AtomicBoolean( + // configuration.getAttribute( + // DOCKERFILE_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(ILaunchConfiguration launchConfig) { + public boolean isValid(final ILaunchConfiguration launchConfig) { try { - if (launchConfig.getAttribute(SOURCE_PATH_LOCATION, "").isEmpty()) { + 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 (sourcePathLocation.isEmpty() || sourcePath == null) { + setErrorMessage( + LaunchMessages.getString(BUILD_CONTEXT_PATH_MISSING)); 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); @@ -241,16 +447,31 @@ public class BuildDockerImageLaunchConfigurationMainTab @Override public void performApply( final ILaunchConfigurationWorkingCopy configuration) { - configuration.setAttribute(SOURCE_PATH_LOCATION, - this.sourcePathLocationText.getText()); - configuration.setAttribute(SOURCE_PATH_WORKSPACE_RELATIVE_LOCATION, - this.sourcePathWorkspaceRelativeLocation); 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.get()); + // configuration.setAttribute(DOCKERFILE_PATH, + // this.dockerFilePathText.getText()); + // configuration.setAttribute(DOCKERFILE_PATH_WORKSPACE_RELATIVE_LOCATION, + // this.dockerFilePathWorkspaceRelative.get()); + 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 @@ -258,7 +479,24 @@ public class BuildDockerImageLaunchConfigurationMainTab return LaunchMessages.getString(TAB_NAME); } - protected class LaunchConfigurationChangeListener extends SelectionAdapter + /** + * 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 @@ -271,4 +509,5 @@ public class BuildDockerImageLaunchConfigurationMainTab updateLaunchConfigurationDialog(); } } + } diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/BuildDockerImageShortcut.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/BuildDockerImageShortcut.java index dac9302215..f780ef3d7f 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/BuildDockerImageShortcut.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/BuildDockerImageShortcut.java @@ -29,6 +29,7 @@ import org.eclipse.debug.core.ILaunchManager; import org.eclipse.debug.ui.DebugUITools; import org.eclipse.debug.ui.IDebugModelPresentation; import org.eclipse.debug.ui.ILaunchShortcut; +import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.ILabelProviderListener; @@ -36,8 +37,10 @@ import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.linuxtools.docker.core.DockerConnectionManager; import org.eclipse.linuxtools.docker.core.IDockerConnection; +import org.eclipse.linuxtools.docker.core.IDockerImageBuildOptions; import org.eclipse.linuxtools.docker.ui.Activator; import org.eclipse.linuxtools.internal.docker.ui.SWTImagesFactory; +import org.eclipse.linuxtools.internal.docker.ui.wizards.ImageBuildDialog; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; @@ -67,7 +70,7 @@ public class BuildDockerImageShortcut implements ILaunchShortcut { } public void launch(IResource resource, String mode) { - ILaunchConfiguration config = findLaunchConfiguration(resource, mode); + ILaunchConfiguration config = findLaunchConfiguration(resource); if (config != null) { DebugUITools.launch(config, mode); } @@ -79,13 +82,10 @@ public class BuildDockerImageShortcut implements ILaunchShortcut { * * @param resource * The Dockerfile to look up launch for. - * @param mode - * Launch mode. * * @return A re-useable config or <code>null</code> if none. */ - protected ILaunchConfiguration findLaunchConfiguration(IResource resource, - String mode) { + protected ILaunchConfiguration findLaunchConfiguration(IResource resource) { ILaunchConfiguration configuration = null; ILaunchConfigurationType configType = getLaunchConfigType(); List<ILaunchConfiguration> candidateConfigs = Collections.emptyList(); @@ -97,8 +97,9 @@ public class BuildDockerImageShortcut implements ILaunchShortcut { String sourcePath = config.getAttribute( IBuildDockerImageLaunchConfigurationConstants.SOURCE_PATH_LOCATION, ""); //$NON-NLS-1$ - boolean workspaceRelative = config - .getAttribute(IBuildDockerImageLaunchConfigurationConstants.SOURCE_PATH_WORKSPACE_RELATIVE_LOCATION, false); + boolean workspaceRelative = config.getAttribute( + IBuildDockerImageLaunchConfigurationConstants.SOURCE_PATH_WORKSPACE_RELATIVE_LOCATION, + false); IPath dockerfilePath = getPath(sourcePath, workspaceRelative); if (dockerfilePath .equals(resource.getLocation().removeLastSegments(1))) { @@ -118,7 +119,7 @@ public class BuildDockerImageShortcut implements ILaunchShortcut { // one. int candidateCount = candidateConfigs.size(); if (candidateCount < 1) { - configuration = createConfiguration(resource, mode, true); + configuration = createConfiguration(resource); } else if (candidateCount == 1) { configuration = candidateConfigs.get(0); } else { @@ -166,29 +167,12 @@ public class BuildDockerImageShortcut implements ILaunchShortcut { * * @param resource * a Dockerfile file to build - * @param save - * true if the configuration should be saved to the underlying - * resource, and false if it should not be saved. * @return a launch configuration generated for the Dockerfile build. */ - protected ILaunchConfiguration createConfiguration(IResource resource, - @SuppressWarnings("unused") String mode, boolean save) { - ILaunchConfiguration config = null; + protected ILaunchConfiguration createConfiguration( + final IResource resource) { try { - ILaunchConfigurationType configType = getLaunchConfigType(); - ILaunchConfigurationWorkingCopy wc = configType.newInstance(null, - getLaunchManager() - .generateLaunchConfigurationName("Dockerfile[" //$NON-NLS-1$ - + resource.getProject().getName() + "]")); //$NON-NLS-1$ - - wc.setAttribute( - IBuildDockerImageLaunchConfigurationConstants.SOURCE_PATH_LOCATION, - resource.getFullPath().removeLastSegments(1).toString()); - wc.setAttribute( - IBuildDockerImageLaunchConfigurationConstants.SOURCE_PATH_WORKSPACE_RELATIVE_LOCATION, - true); - - IDockerConnection[] connections = DockerConnectionManager + final IDockerConnection[] connections = DockerConnectionManager .getInstance().getConnections(); if (connections.length == 0) { Display.getDefault().syncExec(new Runnable() { @@ -205,27 +189,78 @@ public class BuildDockerImageShortcut implements ILaunchShortcut { }); return null; - } else if (connections.length == 1) { - wc.setAttribute( - IBuildDockerImageLaunchConfigurationConstants.DOCKER_CONNECTION, - connections[0].getName()); } else { - IDockerConnection connection = chooseConnection(connections); - if (connection == null) - return null; - wc.setAttribute( - IBuildDockerImageLaunchConfigurationConstants.DOCKER_CONNECTION, - connection.getName()); - } - if (save) { - config = wc.doSave(); - } else { - config = wc; + final ImageBuildDialog dialog = new ImageBuildDialog( + getActiveWorkbenchShell()); + final int result = dialog.open(); + if (result == IDialogConstants.OK_ID) { + final ILaunchConfigurationType configType = LaunchConfigurationUtils + .getLaunchConfigType( + IBuildDockerImageLaunchConfigurationConstants.CONFIG_TYPE_ID); + final ILaunchConfigurationWorkingCopy wc = configType + .newInstance(null, + DebugPlugin.getDefault().getLaunchManager() + .generateLaunchConfigurationName( + createLaunchConfigurationName( + dialog.getRepoName(), + resource))); // $NON-NLS-1$ + wc.setAttribute( + IBuildDockerImageLaunchConfigurationConstants.SOURCE_PATH_LOCATION, + resource.getFullPath().removeLastSegments(1) + .toString()); + wc.setAttribute( + IBuildDockerImageLaunchConfigurationConstants.SOURCE_PATH_WORKSPACE_RELATIVE_LOCATION, + true); + + final IDockerConnection connection = dialog.getConnection(); + final String repoName = dialog.getRepoName(); + wc.setAttribute(IDockerImageBuildOptions.DOCKER_CONNECTION, + connection.getName()); + wc.setAttribute(IDockerImageBuildOptions.REPO_NAME, + repoName); + return wc.doSave(); + } } } catch (CoreException e) { - e.printStackTrace(); + Activator.log(e); + } + return null; + } + + /** + * Creates a Launch Configuration name from the given repoName or from the + * given resource's project if the repoName was <code>null</code>. + * + * @param imageName the full image name + * @param resource the Dockerfile to use to build the image + * @return the {@link ILaunchConfiguration} name + */ + public static String createLaunchConfigurationName(final String imageName, + final IResource resource) { + if (imageName != null) { + final String repository = BuildDockerImageUtils + .getRepository(imageName); + final String name = BuildDockerImageUtils.getName(imageName); + final String tag = BuildDockerImageUtils.getTag(imageName); + final StringBuilder configNameBuilder = new StringBuilder(); + // image name is the minimum requirement + if (name != null) { + if (repository != null) { + configNameBuilder.append(repository).append('_'); // $NON-NLS-1$ + } + if (name != null) { + configNameBuilder.append(name); + } + if (tag != null) { + configNameBuilder.append(" [").append(tag).append("]"); //$NON-NLS-1$ //$NON-NLS-2$ + } else { + configNameBuilder.append(" [latest]"); //$NON-NLS-1$ + } + return configNameBuilder.toString(); + } } - return config; + return "Dockerfile [" //$NON-NLS-1$ + + resource.getProject().getName() + "]"; //$NON-NLS-1$ } /** diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/BuildDockerImageUtils.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/BuildDockerImageUtils.java new file mode 100644 index 0000000000..4bacf534f7 --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/BuildDockerImageUtils.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2015 Red Hat. + * 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 java.io.File; +import java.util.regex.Matcher; + +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.linuxtools.internal.docker.core.DockerImage; + +/** + * Utility class for building Docker Images + */ +public class BuildDockerImageUtils { + + /** + * Computes the path that can be relative to the workspace or absolute. + * + * @param pathLocation + * the base location + * @param workspaceRelativeLocation + * flag to indicate if the path is relative to the workspace + * location or not. + * @return the path or <code>null</code> if it does not exist + */ + public static IPath getPath(final String pathLocation, + final boolean workspaceRelativeLocation) { + if (workspaceRelativeLocation) { + final IResource member = ResourcesPlugin.getWorkspace().getRoot() + .findMember(new Path(pathLocation)); + if (member != null) { + return member.getLocation(); + } + } else if (new File(pathLocation).exists()) { + return new Path(pathLocation); + } + return null; + } + + /** + * Finds and returns the <code>name</code> part of the given full image + * name. + * + * @param imageName + * the full image name + * @return the <code>name</code> part of the given full name or + * <code>null</code> if it could not be found. + */ + public static String getRepository(final String imageName) { + final Matcher imageNameMatcher = DockerImage.imageNamePattern + .matcher(imageName); + if (imageNameMatcher.matches()) { + final String repository = imageNameMatcher.group("repository"); + return repository; //$NON-NLS-1$ + } + return null; + } + + /** + * Finds and returns the <code>name</code> part of the given full image + * name. + * + * @param imageName + * the full image name + * @return the <code>name</code> part of the given full name or + * <code>null</code> if it could not be found. + */ + public static String getName(final String imageName) { + final Matcher imageNameMatcher = DockerImage.imageNamePattern + .matcher(imageName); + if (imageNameMatcher.matches()) { + return imageNameMatcher.group("name"); //$NON-NLS-1$ + } + return null; + } + + /** + * Finds and returns the <code>tag</code> part of the given full image name. + * + * @param imageName + * the full image name + * @return the <code>tag</code> part of the given full name or + * <code>null</code> if it could not be found. + */ + public static String getTag(final String imageName) { + final Matcher imageNameMatcher = DockerImage.imageNamePattern + .matcher(imageName); + if (imageNameMatcher.matches()) { + final String tag = imageNameMatcher.group("tag"); //$NON-NLS-1$ + return tag; //$NON-NLS-1$ + } + return null; + } +} diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/IBuildDockerImageLaunchConfigurationConstants.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/IBuildDockerImageLaunchConfigurationConstants.java index 52b32c93ad..ec195da431 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/IBuildDockerImageLaunchConfigurationConstants.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/IBuildDockerImageLaunchConfigurationConstants.java @@ -12,13 +12,15 @@ package org.eclipse.linuxtools.internal.docker.ui.launch; import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.linuxtools.docker.core.IDockerImageBuildOptions; /** * Constants used to pass values in the {@link ILaunchConfiguration} to build * Docker Images. * */ -public interface IBuildDockerImageLaunchConfigurationConstants { +public interface IBuildDockerImageLaunchConfigurationConstants + extends IDockerImageBuildOptions { /** * the launch id @@ -34,7 +36,13 @@ public interface IBuildDockerImageLaunchConfigurationConstants { */ public final static String SOURCE_PATH_WORKSPACE_RELATIVE_LOCATION = "sourcePathWorkspaceRelativeLocation"; //$NON-NLS-1$ - /** name of the connection to use to build the Image. */ - public final static String DOCKER_CONNECTION = "dockerConnection"; //$NON-NLS-1$ + /** the path to the dockerfile. */ + public final static String DOCKERFILE_PATH = "dockerfilePath"; //$NON-NLS-1$ + + /** + * marker to indicate if the location above is a workspace-relative + * location. + */ + public final static String DOCKERFILE_PATH_WORKSPACE_RELATIVE_LOCATION = "dockerfilePathWorkspaceRelativeLocation"; //$NON-NLS-1$ } diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/LaunchConfigurationUtils.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/LaunchConfigurationUtils.java index c3d2d73fd9..d6bfe12699 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/LaunchConfigurationUtils.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/LaunchConfigurationUtils.java @@ -39,6 +39,17 @@ public class LaunchConfigurationUtils { private LaunchConfigurationUtils() { // empty } + + /** + * @return the ILaunchConfigurationType for the given configuration type. + * @param configType + * the id of the configuration type + */ + public static ILaunchConfigurationType getLaunchConfigType( + final String configType) { + return DebugPlugin.getDefault().getLaunchManager() + .getLaunchConfigurationType(configType); + } public static ILaunchConfiguration saveLaunchConfiguration( final IDockerContainer container) { diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/LaunchMessages.properties b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/LaunchMessages.properties index 5581b6d00d..0ee5026d15 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/LaunchMessages.properties +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/LaunchMessages.properties @@ -9,13 +9,24 @@ # Red Hat - Initial Contribution ############################################################################### +BuildDockerImageLaunchConfiguration.error.incomplete=Launch configuration to build Docker image is incomplete. + BuildDockerImageLaunchConfigurationMainTab.name=Main -BuildDockerImageLaunchConfigurationMainTab.sourcePathLocation.group.label=Source Path: BuildDockerImageLaunchConfigurationMainTab.connection.group.label=Docker Connection -BuildDockerImageLaunchConfigurationMainTab.browseworkspace.button.label=Browse Workspace... -BuildDockerImageLaunchConfigurationMainTab.browseworkspace.dialog.title=Browse Workspace... -BuildDockerImageLaunchConfigurationMainTab.browseworkspace.dialog.message=Browse Workspace for a Dockerfile -BuildDockerImageLaunchConfigurationMainTab.browsefilesystem.button.label=Browse File System... +BuildDockerImageLaunchConfigurationMainTab.connection.group.tooltip=The docker daemon that will be used to build the image +BuildDockerImageLaunchConfigurationMainTab.buildContextPath.group.label=Build Context Path: +BuildDockerImageLaunchConfigurationMainTab.buildContextPath.missing=Build Context Path is missing or invalid +BuildDockerImageLaunchConfigurationMainTab.buildContextPath.browseworkspace.button.label=Browse Workspace... +BuildDockerImageLaunchConfigurationMainTab.buildContextPath.browseworkspace.dialog.title=Browse Workspace... +BuildDockerImageLaunchConfigurationMainTab.buildContextPath.browsefilesystem.button.label=Browse File System... +BuildDockerImageLaunchConfigurationMainTab.dockerfilePath.group.label=Dockerfile Path: +BuildDockerImageLaunchConfigurationMainTab.repoName.label=Repository name (and optional tag) +BuildDockerImageLaunchConfigurationMainTab.repoName.missing=A repository name is recommended +BuildDockerImageLaunchConfigurationMainTab.options.group.label=Options +BuildDockerImageLaunchConfigurationMainTab.options.quiet.button.label=Suppress the verbose output generated by the containers +BuildDockerImageLaunchConfigurationMainTab.options.noCache.button.label=Do not use cache when building the image +BuildDockerImageLaunchConfigurationMainTab.options.rm.button.label=Remove intermediate containers after a successful build +BuildDockerImageLaunchConfigurationMainTab.options.forceRM.button.label=Always remove intermediate containers ImageBuild.msg=Building Docker Image ImageBuild.error.msg=Error while building Docker Image @@ -25,7 +36,9 @@ ImageBuildShortcutChooseLaunch.msg=Choose a launch configuration to run ImageBuildShortcutConnectionSelection.title=Launch Configuration Selection ImageBuildShortcutChooseConnection.msg=Choose the Docker Connection to use + MissingConnectionError.msg=No Docker connection named ''{0}'' exists. + RunDockerImageLaunchConfiguration.creation.failure=Failed to save launch configuration for the image to run NoConnectionError.msg=No Docker connection exists
\ No newline at end of file diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/validators/ImageNameValidator.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/validators/ImageNameValidator.java new file mode 100644 index 0000000000..402c249b57 --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/validators/ImageNameValidator.java @@ -0,0 +1,38 @@ +package org.eclipse.linuxtools.internal.docker.ui.validators; + +import java.util.regex.Matcher; + +import org.eclipse.core.databinding.validation.IValidator; +import org.eclipse.core.databinding.validation.ValidationStatus; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.linuxtools.internal.docker.core.DockerImage; +import org.eclipse.linuxtools.internal.docker.ui.wizards.WizardMessages; + +/** + * Validates that the image name matches + * [REGISTRY_HOST[:REGISTRY_PORT]/]IMAGE_NAME[:TAG] + */ +public class ImageNameValidator implements IValidator { + + @Override + public IStatus validate(final Object value) { + final String imageName = (String) value; + if (imageName.isEmpty()) { + return ValidationStatus + .cancel(WizardMessages.getString("ImagePull.desc")); //$NON-NLS-1$ + } + final Matcher matcher = DockerImage.imageNamePattern + .matcher(imageName); + if (!matcher.matches()) { + return ValidationStatus.warning(WizardMessages + .getString("ImagePull.name.invalidformat.msg")); //$NON-NLS-1$ + } else if (matcher.group("tag") == null) { //$NON-NLS-1$ + return ValidationStatus.warning( + WizardMessages.getString("ImagePull.assumeLatest.msg")); //$NON-NLS-1$ + + } + return Status.OK_STATUS; + } + +}
\ No newline at end of file diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/validators/package-info.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/validators/package-info.java new file mode 100644 index 0000000000..319edc510a --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/validators/package-info.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2015 Red Hat. + * 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.validators;
\ No newline at end of file diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageBuildDialog.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageBuildDialog.java new file mode 100644 index 0000000000..581d44a0c2 --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageBuildDialog.java @@ -0,0 +1,340 @@ +/******************************************************************************* + * Copyright (c) 2015 Red Hat. + * 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.wizards; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.core.databinding.Binding; +import org.eclipse.core.databinding.DataBindingContext; +import org.eclipse.core.databinding.beans.BeanProperties; +import org.eclipse.core.databinding.observable.ChangeEvent; +import org.eclipse.core.databinding.observable.IChangeListener; +import org.eclipse.core.databinding.validation.ValidationStatus; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.databinding.swt.ISWTObservableValue; +import org.eclipse.jface.databinding.swt.WidgetProperties; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.fieldassist.ComboContentAdapter; +import org.eclipse.jface.fieldassist.ContentProposal; +import org.eclipse.jface.fieldassist.ContentProposalAdapter; +import org.eclipse.jface.fieldassist.IContentProposal; +import org.eclipse.jface.fieldassist.IContentProposalProvider; +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.linuxtools.docker.core.DockerConnectionManager; +import org.eclipse.linuxtools.docker.core.IDockerConnection; +import org.eclipse.linuxtools.docker.core.IDockerContainer; +import org.eclipse.linuxtools.internal.docker.ui.SWTImagesFactory; +import org.eclipse.linuxtools.internal.docker.ui.databinding.BaseDatabindingModel; +import org.eclipse.linuxtools.internal.docker.ui.validators.ImageNameValidator; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +/** + * {@link Dialog} to specify Docker Image build options at launch time. + */ +public class ImageBuildDialog extends Dialog { + + private final ImageBuildDialogModel model = new ImageBuildDialogModel(); + private final DataBindingContext dbc = new DataBindingContext(); + + public ImageBuildDialog(Shell parentShell) { + super(parentShell); + } + + @Override + protected void configureShell(final Shell shell) { + super.configureShell(shell); + setShellStyle(getShellStyle() | SWT.RESIZE); + shell.setText(WizardMessages.getString("ImageBuildDialog.title")); //$NON-NLS-1$ + } + + @Override + protected Point getInitialSize() { + return new Point(400, super.getInitialSize().y); + } + + /** + * Disable the 'OK' button by default + */ + @Override + protected Button createButton(Composite parent, int id, String label, + boolean defaultButton) { + final Button button = super.createButton(parent, id, label, + defaultButton); + if (id == IDialogConstants.OK_ID) { + button.setEnabled(false); + } + return button; + } + + @Override + protected Control createDialogArea(final Composite parent) { + final int COLUMNS = 2; + final Composite container = new Composite(parent, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL) + .span(COLUMNS, 1).grab(true, false).applyTo(container); + GridLayoutFactory.fillDefaults().numColumns(COLUMNS).margins(10, 10) + .applyTo(container); + final Label explanationLabel = new Label(container, SWT.NONE); + explanationLabel.setText( + WizardMessages.getString("ImageBuildDialog.explanationLabel")); //$NON-NLS-1$ + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .span(COLUMNS, 1).grab(false, false).applyTo(explanationLabel); + final Label containerLabel = new Label(container, SWT.NONE); + containerLabel.setText( + WizardMessages.getString("ImageBuildDialog.connectionLabel")); //$NON-NLS-1$ + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(false, false).applyTo(containerLabel); + final Combo containerSelectionCombo = new Combo(container, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(true, false).applyTo(containerSelectionCombo); + final ComboViewer connectionSelectionComboViewer = new ComboViewer( + containerSelectionCombo); + connectionSelectionComboViewer + .setContentProvider(new ArrayContentProvider()); + final List<String> connectionNames = model.getConnectionNames(); + connectionSelectionComboViewer.setInput(connectionNames); + new ContentProposalAdapter(containerSelectionCombo, + new ComboContentAdapter() { + @Override + public void insertControlContents(Control control, + String text, int cursorPosition) { + final Combo combo = (Combo) control; + final Point selection = combo.getSelection(); + combo.setText(text); + selection.x = text.length(); + selection.y = selection.x; + combo.setSelection(selection); + } + }, getConnectionNameContentProposalProvider( + containerSelectionCombo), + null, null); + final Label repoNameLabel = new Label(container, SWT.NONE); + repoNameLabel.setText( + WizardMessages.getString("ImageBuildDialog.repoNameLabel")); //$NON-NLS-1$ + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(false, false).applyTo(repoNameLabel); + final Text repoNameText = new Text(container, SWT.BORDER); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(true, false).applyTo(repoNameText); + final ISWTObservableValue connnectionNameObservable = WidgetProperties + .selection().observe(connectionSelectionComboViewer.getCombo()); + // pre-select with first connection + if (!connectionNames.isEmpty()) { + model.setConnectionName(connectionNames.get(0)); + } + // error message + final Composite errorContainer = new Composite(container, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL) + .span(COLUMNS, 1).grab(true, true).applyTo(errorContainer); + GridLayoutFactory.fillDefaults().margins(6, 6).numColumns(2) + .applyTo(errorContainer); + + final Label errorMessageIcon = new Label(errorContainer, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .hint(20, SWT.DEFAULT).applyTo(errorMessageIcon); + final Label errorMessageLabel = new Label(errorContainer, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(true, false).applyTo(errorMessageLabel); + dbc.bindValue(connnectionNameObservable, + BeanProperties + .value(ImageBuildDialogModel.class, + ImageBuildDialogModel.CONNECTION_NAME) + .observe(model)); + final ISWTObservableValue repoNameObservable = WidgetProperties + .text(SWT.Modify).observe(repoNameText); + + dbc.bindValue(repoNameObservable, + BeanProperties + .value(ImageBuildDialogModel.class, + ImageBuildDialogModel.REPO_NAME) + .observe(model)); + // must be called after bindings were set + setupValidationSupport(errorMessageIcon, errorMessageLabel); + return container; + } + + private void setupValidationSupport(final Label errorMessageIcon, + final Label errorMessageLabel) { + for (@SuppressWarnings("unchecked") + Iterator<Binding> iterator = dbc.getBindings().iterator(); iterator + .hasNext();) { + final Binding binding = iterator.next(); + binding.getModel().addChangeListener(onBuildSettingsChanged( + errorMessageIcon, errorMessageLabel)); + } + } + + private IChangeListener onBuildSettingsChanged(final Label errorMessageIcon, + final Label errorMessageLabel) { + + return new IChangeListener() { + + @Override + public void handleChange(ChangeEvent event) { + final IStatus status = validateInput(); + if (Display.getCurrent() == null) { + return; + } + Display.getCurrent().syncExec(new Runnable() { + + @Override + public void run() { + if (status.isOK()) { + errorMessageIcon.setVisible(false); + errorMessageLabel.setVisible(false); + setOkButtonEnabled(true); + } else if (status.matches(IStatus.WARNING)) { + errorMessageIcon.setVisible(true); + errorMessageIcon + .setImage(SWTImagesFactory.DESC_WARNING + .createImage()); + errorMessageLabel.setVisible(true); + errorMessageLabel.setText(status.getMessage()); + setOkButtonEnabled(true); + } else if (status.matches(IStatus.ERROR)) { + if (status.getMessage() != null + && !status.getMessage().isEmpty()) { + errorMessageIcon.setVisible(true); + errorMessageIcon + .setImage(SWTImagesFactory.DESC_ERROR + .createImage()); + errorMessageLabel.setVisible(true); + errorMessageLabel.setText(status.getMessage()); + } + setOkButtonEnabled(false); + } + } + }); + } + }; + } + + /** + * Validates that the selected {@link IDockerConnection} exists and that the + * optional image name is valid. + * + * @return a validation status + */ + private IStatus validateInput() { + final String selectedConnectionName = model.getConnectionName(); + final String repoName = model.getRepoName(); + if (selectedConnectionName == null + || selectedConnectionName.isEmpty()) { + return Status.CANCEL_STATUS; + } else + if (!model.getConnectionNames().contains(selectedConnectionName)) { + return ValidationStatus.error(WizardMessages.getFormattedString( + "ImageBuildDialog.error.unknownConnection", //$NON-NLS-1$ + selectedConnectionName)); + } else if (repoName == null || repoName.isEmpty()) { + return ValidationStatus.warning(WizardMessages + .getString("ImageBuildDialog.warning.missingRepoName")); //$NON-NLS-1$ + } else { + final ImageNameValidator imageNameValidator = new ImageNameValidator(); + return imageNameValidator.validate(repoName); + } + } + + public IDockerConnection getConnection() { + return DockerConnectionManager.getInstance() + .findConnection(model.connectionName); + } + + public String getRepoName() { + return model.getRepoName(); + } + + /** + * Creates an {@link IContentProposalProvider} to propose + * {@link IDockerContainer} names based on the current text. + * + * @param items + * @return + */ + private IContentProposalProvider getConnectionNameContentProposalProvider( + final Combo connectionNamesSelectionCombo) { + return new IContentProposalProvider() { + + @Override + public IContentProposal[] getProposals(final String contents, + final int position) { + final List<IContentProposal> proposals = new ArrayList<>(); + for (String connectionName : connectionNamesSelectionCombo + .getItems()) { + if (connectionName.contains(contents)) { + proposals.add(new ContentProposal(connectionName, + connectionName, connectionName, position)); + } + } + return proposals.toArray(new IContentProposal[0]); + } + }; + } + + private void setOkButtonEnabled(final boolean enabled) { + getButton(IDialogConstants.OK_ID).setEnabled(enabled); + } + + class ImageBuildDialogModel extends BaseDatabindingModel { + + public static final String CONNECTION_NAME = "connectionName"; //$NON-NLS-1$ + + public static final String REPO_NAME = "repoName"; //$NON-NLS-1$ + + private String connectionName; + + private String repoName; + + private final List<String> connectionNames = DockerConnectionManager + .getInstance().getConnectionNames(); + + public String getRepoName() { + return repoName; + } + + public List<String> getConnectionNames() { + return connectionNames; + } + + public void setRepoName(final String repoName) { + firePropertyChange(REPO_NAME, this.repoName, + this.repoName = repoName); + } + + public String getConnectionName() { + return connectionName; + } + + public void setConnectionName(final String connectionName) { + firePropertyChange(CONNECTION_NAME, this.connectionName, + this.connectionName = connectionName); + } + + } + +} diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImagePullPage.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImagePullPage.java index cc88749b5b..07ed83344d 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImagePullPage.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImagePullPage.java @@ -12,16 +12,11 @@ package org.eclipse.linuxtools.internal.docker.ui.wizards; import java.util.regex.Matcher; -import java.util.regex.Pattern; import org.eclipse.core.databinding.DataBindingContext; import org.eclipse.core.databinding.UpdateValueStrategy; import org.eclipse.core.databinding.beans.BeanProperties; import org.eclipse.core.databinding.observable.value.IObservableValue; -import org.eclipse.core.databinding.validation.IValidator; -import org.eclipse.core.databinding.validation.ValidationStatus; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; import org.eclipse.jface.databinding.swt.WidgetProperties; import org.eclipse.jface.databinding.wizard.WizardPageSupport; import org.eclipse.jface.layout.GridDataFactory; @@ -29,8 +24,10 @@ import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.linuxtools.docker.core.IDockerConnection; import org.eclipse.linuxtools.docker.ui.wizards.ImageSearch; +import org.eclipse.linuxtools.internal.docker.core.DockerImage; import org.eclipse.linuxtools.internal.docker.ui.SWTImagesFactory; import org.eclipse.linuxtools.internal.docker.ui.commands.CommandUtils; +import org.eclipse.linuxtools.internal.docker.ui.validators.ImageNameValidator; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; @@ -50,15 +47,6 @@ public class ImagePullPage extends WizardPage { private final DataBindingContext dbc; private final IDockerConnection connection; - private static final String REGISTRY_HOST = "[a-zA-Z0-9]+([._-][a-zA-Z0-9]+)*"; //$NON-NLS-1$ - private static final String REGISTRY_PORT = "[0-9]+"; //$NON-NLS-1$ - private static final String REPOSITORY = "[a-z0-9]+([._-][a-z0-9]+)*"; //$NON-NLS-1$ - private static final String NAME = "[a-z0-9]+([._-][a-z0-9]+)*"; //$NON-NLS-1$ - private static final String TAG = "[a-zA-Z0-9]+([._-][a-zA-Z0-9]+)*"; //$NON-NLS-1$ - private static final Pattern imageNamePattern = Pattern.compile("(" //$NON-NLS-1$ - + REGISTRY_HOST + "(\\:" + REGISTRY_PORT + ")?/)?" + "(" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - + REPOSITORY + "/)?" + NAME + "(?<tag>\\:" + TAG + ")?"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - public ImagePullPage(final IDockerConnection connection) { super("ImagePullPage", //$NON-NLS-1$ WizardMessages.getString("ImagePull.label"), //$NON-NLS-1$ @@ -76,7 +64,7 @@ public class ImagePullPage extends WizardPage { } public String getImageName() { - final Matcher matcher = imageNamePattern + final Matcher matcher = DockerImage.imageNamePattern .matcher(this.model.getImageName()); // Matcher#matches() must be called before any attempt to access a given // named capturing-group. @@ -151,31 +139,4 @@ public class ImagePullPage extends WizardPage { }; } - /** - * Validates that the image name matches - * [REGISTRY_HOST[:REGISTRY_PORT]/]IMAGE_NAME[:TAG] - */ - public static class ImageNameValidator implements IValidator { - - @Override - public IStatus validate(final Object value) { - final String imageName = (String) value; - if (imageName.isEmpty()) { - return ValidationStatus - .cancel(WizardMessages.getString("ImagePull.desc")); //$NON-NLS-1$ - } - final Matcher matcher = imageNamePattern.matcher(imageName); - if (!matcher.matches()) { - return ValidationStatus.warning(WizardMessages - .getString("ImagePull.name.invalidformat.msg")); //$NON-NLS-1$ - } else if (matcher.group("tag") == null) { //$NON-NLS-1$ - return ValidationStatus.warning( - WizardMessages.getString("ImagePull.assumeLatest.msg")); //$NON-NLS-1$ - - } - return Status.OK_STATUS; - } - - } - } diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageRunSelectionPage.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageRunSelectionPage.java index 880ca13f9e..76d4e7572f 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageRunSelectionPage.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageRunSelectionPage.java @@ -174,6 +174,8 @@ public class ImageRunSelectionPage extends WizardPage { final ImageSelectionValidator imageSelectionValidator = new ImageSelectionValidator( imageSelectionObservable); dbc.addValidationStatusProvider(imageSelectionValidator); + imageSelectionObservable + .addValueChangeListener(onImageSelectionChange()); final IObservableValue containerNameObservable = BeanProperties .value(ImageRunSelectionModel.class, ImageRunSelectionModel.CONTAINER_NAME) @@ -181,7 +183,6 @@ public class ImageRunSelectionPage extends WizardPage { final ContainerNameValidator containerNameValidator = new ContainerNameValidator( model.getSelectedConnection(), containerNameObservable); dbc.addValidationStatusProvider(containerNameValidator); - // setControl(container); } diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/WizardMessages.properties b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/WizardMessages.properties index e8d495a389..239ae0d09f 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/WizardMessages.properties +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/WizardMessages.properties @@ -305,4 +305,11 @@ ContainerDataVolumeDialog.readOnlyButtonTooltip=Specify if the mounted host dire ContainerDataVolumeDialog.fileButton=File... ContainerDataVolumeDialog.containerMountButton=Mount a data volume container ContainerDataVolumeDialog.containerSelectionLabel=Container: -ContainerDataVolumeDialog.volumeWarning=The selected container does not define a {0} volume.
\ No newline at end of file +ContainerDataVolumeDialog.volumeWarning=The selected container does not define a {0} volume. + +ImageBuildDialog.title=Docker Image Build Configuration +ImageBuildDialog.explanationLabel=Select a connection and a repository name +ImageBuildDialog.connectionLabel=Connection: +ImageBuildDialog.repoNameLabel=Repository Name: +ImageBuildDialog.error.unknownConnection=Connection {0} does not exist. +ImageBuildDialog.warning.missingRepoName=A repository name is recommended. |