diff options
author | Xavier Coulon | 2015-08-31 10:52:35 +0000 |
---|---|---|
committer | Roland Grunberg | 2015-09-08 18:18:19 +0000 |
commit | caaa4b2f3a452981d6b6c6353a75f707a716a953 (patch) | |
tree | 0415de921c70db6a6da150536d2dc248077db069 | |
parent | 2fdb20264afaec512775beff543e9c76dd6ff35f (diff) | |
download | org.eclipse.linuxtools-caaa4b2f3a452981d6b6c6353a75f707a716a953.tar.gz org.eclipse.linuxtools-caaa4b2f3a452981d6b6c6353a75f707a716a953.tar.xz org.eclipse.linuxtools-caaa4b2f3a452981d6b6c6353a75f707a716a953.zip |
Bug 475881 - Pull image workflow improvement
Restored the PullImage wizard as the first step when
pulling an image.
The "Search..." buttons opens the SearchImage dialog with
search term prefilled from the current image name.
If no tag is specified, then 'latest' is assumed.
The validation only raises warnings to avoid preventing
the user to attempt to pull an image ( the Docker daemon
may eventually raise an error).
Added some JUnit tests to validate the image name patterns
Change-Id: I7b7fef9e8ed9bbbc7701880af44a4e9f412a1543
Signed-off-by: Xavier Coulon <xcoulon@redhat.com>
Reviewed-on: https://git.eclipse.org/r/55098
Reviewed-by: Roland Grunberg <rgrunber@redhat.com>
Tested-by: Roland Grunberg <rgrunber@redhat.com>
22 files changed, 489 insertions, 65 deletions
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 4454a2a3ba..001243cd22 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 @@ -1054,6 +1054,7 @@ public class DockerConnection implements IDockerConnection, Closeable { try { DockerProgressHandler d = new DockerProgressHandler(handler); client.pull(id, d); + listImages(); } catch (com.spotify.docker.client.DockerRequestException e) { throw new DockerException(e.message()); } catch (com.spotify.docker.client.DockerException e) { diff --git a/containers/org.eclipse.linuxtools.docker.ui.tests/.classpath b/containers/org.eclipse.linuxtools.docker.ui.tests/.classpath new file mode 100644 index 0000000000..3bc247511f --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui.tests/.classpath @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/containers/org.eclipse.linuxtools.docker.ui.tests/.project b/containers/org.eclipse.linuxtools.docker.ui.tests/.project new file mode 100644 index 0000000000..dec8106d9d --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui.tests/.project @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.eclipse.linuxtools.docker.ui.tests</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.ManifestBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.SchemaBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + <nature>org.eclipse.pde.PluginNature</nature> + </natures> +</projectDescription> diff --git a/containers/org.eclipse.linuxtools.docker.ui.tests/.settings/org.eclipse.jdt.core.prefs b/containers/org.eclipse.linuxtools.docker.ui.tests/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..7341ab1683 --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui.tests/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/containers/org.eclipse.linuxtools.docker.ui.tests/META-INF/MANIFEST.MF b/containers/org.eclipse.linuxtools.docker.ui.tests/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..0fd1a3a4a9 --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui.tests/META-INF/MANIFEST.MF @@ -0,0 +1,10 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Tests +Bundle-SymbolicName: org.eclipse.linuxtools.docker.ui.tests +Bundle-Version: 1.1.0.qualifier +Export-Package: org.eclipse.linuxtools.internal.docker.ui.wizards +Require-Bundle: org.junit;bundle-version="4.12.0", + org.eclipse.linuxtools.docker.ui;bundle-version="1.0.0", + org.eclipse.core.runtime, + org.hamcrest.library;bundle-version="1.3.0" diff --git a/containers/org.eclipse.linuxtools.docker.ui.tests/build.properties b/containers/org.eclipse.linuxtools.docker.ui.tests/build.properties new file mode 100644 index 0000000000..b107977f4e --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui.tests/build.properties @@ -0,0 +1,3 @@ +source.. = src/ +bin.includes = META-INF/,\ + . diff --git a/containers/org.eclipse.linuxtools.docker.ui.tests/pom.xml b/containers/org.eclipse.linuxtools.docker.ui.tests/pom.xml new file mode 100644 index 0000000000..5ae7ea2846 --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui.tests/pom.xml @@ -0,0 +1,12 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.eclipse.linuxtools</groupId> + <artifactId>org.eclipse.linuxtools.docker</artifactId> + <version>1.1.0-SNAPSHOT</version> + </parent> + <artifactId>org.eclipse.linuxtools.docker.ui.tests</artifactId> + <packaging>eclipse-test-plugin</packaging> + +</project>
\ 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 new file mode 100644 index 0000000000..b831072903 --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImagePullPatternTest.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * 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 org.eclipse.core.runtime.IStatus; +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; + +@RunWith(Parameterized.class) +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[][] { + match("", IStatus.CANCEL), + match("£", IStatus.WARNING), + match("wildfly", IStatus.WARNING), + match("jboss/", IStatus.WARNING), + match("jboss/wildfly", IStatus.WARNING), + 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:", 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), + }; + } + + @Parameter(value=0) + public String imageName; + @Parameter(value=1) + public int expectedSeverity; + + + @Test + public void verifyData() throws Exception { + final IStatus status = new ImagePullPage.ImageNameValidator().validate(imageName); + // then + Assert.assertEquals(expectedSeverity, status.getSeverity()); + } + +} diff --git a/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/wizards/package-info.java b/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/wizards/package-info.java new file mode 100644 index 0000000000..6ccd8f603d --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/wizards/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.wizards;
\ No newline at end of file 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 71ca14c624..8ecbe1a709 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/META-INF/MANIFEST.MF +++ b/containers/org.eclipse.linuxtools.docker.ui/META-INF/MANIFEST.MF @@ -28,4 +28,5 @@ Bundle-ActivationPolicy: lazy Bundle-Localization: plugin Export-Package: org.eclipse.linuxtools.docker.ui, org.eclipse.linuxtools.docker.ui.launch, - org.eclipse.linuxtools.internal.docker.ui.preferences + org.eclipse.linuxtools.internal.docker.ui.preferences, + 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/wizards/ImageSearch.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/docker/ui/wizards/ImageSearch.java index 6e183d0e77..0b4548f82c 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/docker/ui/wizards/ImageSearch.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/docker/ui/wizards/ImageSearch.java @@ -14,8 +14,6 @@ package org.eclipse.linuxtools.docker.ui.wizards; import org.eclipse.jface.wizard.Wizard; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.linuxtools.docker.core.IDockerConnection; -import org.eclipse.linuxtools.docker.core.IDockerImageSearchResult; -import org.eclipse.linuxtools.internal.docker.ui.wizards.DockerImageTagSearchResult; import org.eclipse.linuxtools.internal.docker.ui.wizards.ImageSearchModel; import org.eclipse.linuxtools.internal.docker.ui.wizards.ImageSearchPage; import org.eclipse.linuxtools.internal.docker.ui.wizards.ImageTagSelectionPage; @@ -41,11 +39,16 @@ public class ImageSearch extends Wizard { /* * Default Constructor + * + * @param connection + * the current connection to a target Docker daemon + * @param name + * the current image name or <code>null</code> if not applicable */ - public ImageSearch(final IDockerConnection connection) { + public ImageSearch(final IDockerConnection connection, final String name) { setWindowTitle(WizardMessages.getString("ImageSearch.title")); //$NON-NLS-1$ setNeedsProgressMonitor(true); - this.imageSearchModel = new ImageSearchModel(connection); + this.imageSearchModel = new ImageSearchModel(connection, name); this.imageSearchPage = new ImageSearchPage(this.imageSearchModel); this.imageTagSelectionPage = new ImageTagSelectionPage( this.imageSearchModel); @@ -67,11 +70,9 @@ public class ImageSearch extends Wizard { return true; } - public IDockerImageSearchResult getSelectedImage() { - return this.imageSearchPage.getSelectedImage(); + public String getSelectedImage() { + return this.imageSearchPage.getSelectedImage().getName() + ":" + + this.imageTagSelectionPage.getSelectedImageTag().getName(); } - public DockerImageTagSearchResult getSelectedImageTag() { - return this.imageTagSelectionPage.getSelectedImageTag(); - } } diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/PullImageCommandHandler.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/PullImageCommandHandler.java index 8d477ddd28..f0111dd2c9 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/PullImageCommandHandler.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/PullImageCommandHandler.java @@ -23,6 +23,7 @@ import org.eclipse.linuxtools.docker.ui.wizards.ImageSearch; import org.eclipse.linuxtools.internal.docker.core.DockerConnection; import org.eclipse.linuxtools.internal.docker.ui.views.DVMessages; import org.eclipse.linuxtools.internal.docker.ui.views.ImagePullProgressHandler; +import org.eclipse.linuxtools.internal.docker.ui.wizards.ImagePull; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.handlers.HandlerUtil; @@ -43,20 +44,19 @@ public class PullImageCommandHandler extends AbstractHandler { final IWorkbenchPart activePart = HandlerUtil.getActivePart(event); final IDockerConnection connection = CommandUtils .getCurrentConnection(activePart); - final ImageSearch wizard = new ImageSearch(connection); + final ImagePull wizard = new ImagePull(connection); final boolean pullImage = CommandUtils.openWizard(wizard, HandlerUtil.getActiveShell(event)); if (pullImage) { - performPullImage(connection, wizard.getSelectedImage().getName(), - wizard.getSelectedImageTag().getName()); + performPullImage(connection, wizard.getImageName()); } return null; } private void performPullImage(final IDockerConnection connection, - final String imageName, final String tagName) { + final String imageName) { final Job pullImageJob = new Job(DVMessages - .getFormattedString(PULL_IMAGE_JOB_TITLE, imageName, tagName)) { + .getFormattedString(PULL_IMAGE_JOB_TITLE, imageName)) { @Override protected IStatus run(final IProgressMonitor monitor) { @@ -65,8 +65,7 @@ public class PullImageCommandHandler extends AbstractHandler { // pull the image and let the progress // handler refresh the images when done try { - ((DockerConnection) connection).pullImage( - imageName + ":" + tagName, + ((DockerConnection) connection).pullImage(imageName, new ImagePullProgressHandler(connection, imageName)); } catch (final DockerException e) { diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/RemoveConnectionCommandHandler.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/RemoveConnectionCommandHandler.java index 16888bde39..ca0fa146b4 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/RemoveConnectionCommandHandler.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/RemoveConnectionCommandHandler.java @@ -39,7 +39,6 @@ public class RemoveConnectionCommandHandler extends AbstractHandler { } viewer.refresh(); } - // return must be null, javadoc says. return null; } diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/views/DVMessages.properties b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/views/DVMessages.properties index c2afef50c5..335f00837c 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/views/DVMessages.properties +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/views/DVMessages.properties @@ -173,7 +173,7 @@ ContainerCommitError.msg=Error committing container ImageBuild.msg=Building Image ImagePull.msg=Pulling Image -ImagePull.title=Pulling {0}:{1} +ImagePull.title=Pulling {0} ImagePush.msg=Pushing Image ImagePush.title=Pushing Image <{0}> diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImagePull.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImagePull.java new file mode 100644 index 0000000000..382e7e28a1 --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImagePull.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * 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 org.eclipse.jface.wizard.Wizard; +import org.eclipse.linuxtools.docker.core.DockerException; +import org.eclipse.linuxtools.docker.core.IDockerConnection; +import org.eclipse.linuxtools.docker.core.IDockerImage; + +/** + * + */ +public class ImagePull extends Wizard { + + private final ImagePullPage imagePullPage; + + /** + * Constructor when an {@link IDockerConnection} has been selected to run an + * {@link IDockerImage}. + * + * @param connection + * the {@link IDockerConnection} pointing to a specific Docker + * daemon/host. + * @throws DockerException + */ + public ImagePull(final IDockerConnection connection) { + super(); + setWindowTitle(WizardMessages.getString("ImagePull.title")); //$NON-NLS-1$ + this.imagePullPage = new ImagePullPage(connection); + } + + @Override + public void addPages() { + addPage(imagePullPage); + } + + @Override + public boolean canFinish() { + return this.imagePullPage.isPageComplete(); + } + + @Override + public boolean performFinish() { + return true; + } + + public String getImageName() { + return this.imagePullPage.getImageName(); + } + +} 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 new file mode 100644 index 0000000000..cc88749b5b --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImagePullPage.java @@ -0,0 +1,181 @@ +/******************************************************************************* + * 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.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; +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.ui.SWTImagesFactory; +import org.eclipse.linuxtools.internal.docker.ui.commands.CommandUtils; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; + +/** + * + */ +public class ImagePullPage extends WizardPage { + + private final ImagePullPageModel model; + 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$ + SWTImagesFactory.DESC_BANNER_REPOSITORY); + setMessage(WizardMessages.getString("ImagePull.desc")); //$NON-NLS-1$ + this.model = new ImagePullPageModel(); + this.dbc = new DataBindingContext(); + this.connection = connection; + } + + @Override + public void dispose() { + dbc.dispose(); + super.dispose(); + } + + public String getImageName() { + final Matcher matcher = imageNamePattern + .matcher(this.model.getImageName()); + // Matcher#matches() must be called before any attempt to access a given + // named capturing-group. + if (matcher.matches() && matcher.group("tag") == null) { //$NON-NLS-1$ + return this.model.getImageName() + ":latest"; //$NON-NLS-1$ + } + + return this.model.getImageName(); + } + + @Override + public void createControl(Composite parent) { + parent.setLayout(new GridLayout()); + final Composite container = new Composite(parent, SWT.NONE); + GridLayoutFactory.fillDefaults().numColumns(3).margins(6, 6) + .applyTo(container); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).span(1, 1) + .grab(true, false).applyTo(container); + + // Image name + final Label imageNameLabel = new Label(container, SWT.NONE); + imageNameLabel + .setText(WizardMessages.getString("ImagePull.name.label")); //$NON-NLS-1$ + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(false, false).applyTo(imageNameLabel); + + final Text imageNameText = new Text(container, SWT.BORDER); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(true, false).applyTo(imageNameText); + imageNameText.setToolTipText( + WizardMessages.getString("ImagePull.name.tooltip")); //$NON-NLS-1$ + // binding + final IObservableValue imgeNameObservable = BeanProperties + .value(ImagePullPageModel.class, ImagePullPageModel.IMAGE_NAME) + .observe(model); + dbc.bindValue(WidgetProperties.text(SWT.Modify).observe(imageNameText), + imgeNameObservable, new UpdateValueStrategy() + .setAfterConvertValidator(new ImageNameValidator()), + null); + // search + final Button searchButton = new Button(container, SWT.NONE); + searchButton + .setText(WizardMessages.getString("ImagePull.search.label")); //$NON-NLS-1$ + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(false, false).applyTo(searchButton); + searchButton.addSelectionListener(onSearchImage()); + + // setup validation support + WizardPageSupport.create(this, dbc); + setControl(container); + } + + /** + * Opens the {@link ImageSearch} dialog with current image name pre-filled. + * + * @return + */ + private SelectionListener onSearchImage() { + return new SelectionAdapter() { + + @Override + public void widgetSelected(final SelectionEvent e) { + final ImageSearch imageSearchWizard = new ImageSearch( + ImagePullPage.this.connection, + ImagePullPage.this.model.getImageName()); + final boolean completed = CommandUtils + .openWizard(imageSearchWizard, getShell()); + if (completed) { + model.setImageName(imageSearchWizard.getSelectedImage()); + } + } + }; + } + + /** + * 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/ImagePullPageModel.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImagePullPageModel.java new file mode 100644 index 0000000000..62534a9ac4 --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImagePullPageModel.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * 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 org.eclipse.linuxtools.internal.docker.ui.databinding.BaseDatabindingModel; + +/** + * + */ +public class ImagePullPageModel extends BaseDatabindingModel { + + public static final String IMAGE_NAME = "imageName"; + + private String imageName; + + public String getImageName() { + return imageName; + } + + public void setImageName(final String imageName) { + firePropertyChange(IMAGE_NAME, this.imageName, this.imageName = imageName); + } +} 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 147f521a14..41e54f8aae 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 @@ -57,7 +57,6 @@ import org.eclipse.linuxtools.docker.core.DockerException; import org.eclipse.linuxtools.docker.core.IDockerConnection; import org.eclipse.linuxtools.docker.core.IDockerImage; import org.eclipse.linuxtools.docker.core.IDockerImageInfo; -import org.eclipse.linuxtools.docker.core.IDockerImageSearchResult; import org.eclipse.linuxtools.docker.ui.Activator; import org.eclipse.linuxtools.docker.ui.wizards.ImageSearch; import org.eclipse.linuxtools.internal.docker.ui.SWTImagesFactory; @@ -691,17 +690,14 @@ public class ImageRunSelectionPage extends WizardPage { public void widgetSelected(SelectionEvent e) { final ImageSearch imageSearchWizard = new ImageSearch( ImageRunSelectionPage.this.model - .getSelectedConnection()); + .getSelectedConnection(), + ImageRunSelectionPage.this.model + .getSelectedImageName()); final boolean completed = CommandUtils .openWizard(imageSearchWizard, getShell()); if (completed) { - final IDockerImageSearchResult selectedImage = imageSearchWizard - .getSelectedImage(); - final DockerImageTagSearchResult selectedImageTag = imageSearchWizard - .getSelectedImageTag(); - model.setSelectedImageName(selectedImage.getName() - + ":" //$NON-NLS-1$ - + selectedImageTag.getName()); + model.setSelectedImageName( + imageSearchWizard.getSelectedImage()); } } }; diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageSearchModel.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageSearchModel.java index c173859459..6cd80f6849 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageSearchModel.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageSearchModel.java @@ -47,8 +47,18 @@ public class ImageSearchModel extends BaseDatabindingModel { private DockerImageTagSearchResult selectedImageTag; - public ImageSearchModel(final IDockerConnection selectedConnection) { + public ImageSearchModel(final IDockerConnection selectedConnection, + String term) { this.selectedConnection = selectedConnection; + // the search term should not contain a tag (eg: 'centos' but not + // 'centos:latest') + if (term == null) { + this.term = null; + } else if (term.indexOf(":") != -1) { //$NON-NLS-1$ + this.term = term.substring(0, term.lastIndexOf(":")); //$NON-NLS-1$ + } else { + this.term = term; + } } public IDockerConnection getSelectedConnection() { diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageSearchPage.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageSearchPage.java index a6baa16824..c32fb68a33 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageSearchPage.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageSearchPage.java @@ -26,8 +26,6 @@ import org.eclipse.core.databinding.beans.BeanProperties; import org.eclipse.core.databinding.beans.PojoProperties; import org.eclipse.core.databinding.observable.list.IObservableList; import org.eclipse.core.databinding.observable.value.IObservableValue; -import org.eclipse.core.databinding.observable.value.IValueChangeListener; -import org.eclipse.core.databinding.observable.value.ValueChangeEvent; import org.eclipse.core.databinding.validation.IValidator; import org.eclipse.core.databinding.validation.ValidationStatus; import org.eclipse.core.runtime.IProgressMonitor; @@ -127,7 +125,6 @@ public class ImageSearchPage extends WizardPage { GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .grab(false, false).applyTo(searchImageButton); searchImageButton.addSelectionListener(onSearchImageButtonSelected()); - searchImageButton.setEnabled(!searchImageText.getText().isEmpty()); // result table final Label searchResultLabel = new Label(container, SWT.NONE); searchResultLabel.setText( @@ -179,16 +176,12 @@ public class ImageSearchPage extends WizardPage { final IObservableValue observableTermModel = BeanProperties .value(ImageSearchModel.class, ImageSearchModel.TERM) .observe(model); - final UpdateValueStrategy strategy = new UpdateValueStrategy(); - strategy.setBeforeSetValidator(new SearchTermValidator()); - final ISWTObservableValue imageSearchTextObservable = WidgetProperties .text(SWT.Modify).observe(searchImageText); - ctx.bindValue(imageSearchTextObservable, observableTermModel, strategy, + ctx.bindValue(imageSearchTextObservable, observableTermModel, + new UpdateValueStrategy().setBeforeSetValidator( + new SearchTermValidator(searchImageButton)), null); - // enable/disable the search button - imageSearchTextObservable - .addValueChangeListener(onTermValueChanged(searchImageButton)); // observe the viewer content searchResultTableViewer .setContentProvider(new ObservableListContentProvider()); @@ -233,26 +226,6 @@ public class ImageSearchPage extends WizardPage { return viewerColumn; } - private IValueChangeListener onTermValueChanged( - final Button searchImageButton) { - return new IValueChangeListener() { - - @Override - public void handleValueChange(final ValueChangeEvent event) { - final String searchTerm = (String) event.getObservableValue() - .getValue(); - final IStatus status = AggregateValidationStatus - .getStatusMaxSeverity( - ctx.getValidationStatusProviders()); - if (searchTerm.isEmpty() || !status.isOK()) { - searchImageButton.setEnabled(false); - } else { - searchImageButton.setEnabled(true); - } - } - }; - } - private TraverseListener onSearchImageTextTraverse() { return new TraverseListener() { @@ -363,18 +336,29 @@ public class ImageSearchPage extends WizardPage { static class SearchTermValidator implements IValidator { + private static final String REPOSITORY = "[a-z0-9]+([._-][a-z0-9]+)*"; + private static final String NAME = "[a-z0-9]+([._-][a-z0-9]+)*"; private static final Pattern termPattern = Pattern - .compile("[a-z0-9]+([._-][a-z0-9]+)*"); //$NON-NLS-1$ + .compile("(" + REPOSITORY + "/)?" + NAME); + + private final Button searchImageButton; + + public SearchTermValidator(final Button searchImageButton) { + this.searchImageButton = searchImageButton; + } @Override public IStatus validate(final Object value) { final String term = (String) value; if (term == null || term.isEmpty()) { + this.searchImageButton.setEnabled(false); return ValidationStatus.info(WizardMessages .getString("ImageSearchPage.description")); //$NON-NLS-1$ } else if (termPattern.matcher(term).matches()) { + this.searchImageButton.setEnabled(true); return Status.OK_STATUS; } else { + this.searchImageButton.setEnabled(false); return ValidationStatus.error(WizardMessages.getFormattedString( "ImageSearchPage.term.invalidformat", //$NON-NLS-1$ termPattern.pattern())); 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 33be568246..cc82a4344c 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 @@ -80,12 +80,14 @@ EditButton.label=Edit Dockerfile SaveButton.label=Save CancelButton.label=Cancel -ImagePull.label=Pull an image: -ImagePull.desc=Specify repository or single image to pull down to the host. ImagePull.title=Pull Image - -ImagePullName.label=Name: -ImagePullName.toolTip=Enter either a REPOSITORY to load all its images or REPOSITORY:TAG to load a single image +ImagePull.label=Pull an image or a repository from the registry +ImagePull.desc=Specify a repository or a single image to pull down to the host. +ImagePull.name.label=Name: +ImagePull.name.tooltip=Enter either a REPOSITORY to load all its images or REPOSITORY:TAG to load a single image +ImagePull.search.label=Search... +ImagePull.name.invalidformat.msg=Image name is invalid.\nExpected [REGISTRY_HOST[:REGISTRY_PORT]/]NAME[:TAG] +ImagePull.assumeLatest.msg=Assuming image tag is 'latest' since none was specified ImagePush.label=Push an image: ImagePush.desc=Specify the name of an image to push to the host. diff --git a/containers/pom.xml b/containers/pom.xml index 5e30cb61b0..70bc153fbd 100644 --- a/containers/pom.xml +++ b/containers/pom.xml @@ -25,6 +25,7 @@ <modules> <module>org.eclipse.linuxtools.docker.core</module> <module>org.eclipse.linuxtools.docker.ui</module> + <module>org.eclipse.linuxtools.docker.ui.tests</module> <module>org.eclipse.linuxtools.docker.docs</module> <module>org.eclipse.linuxtools.docker-feature</module> </modules> |