diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CommandLauncherManager.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CommandLauncherManager.java index e9e6a4f4fb9..79bd82987d1 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CommandLauncherManager.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CommandLauncherManager.java @@ -296,6 +296,35 @@ public class CommandLauncherManager { return bestLauncherFactory; } + private ICommandLauncherFactory getBestFactory(ICBuildConfiguration config) { + // loop through list of factories and return launcher returned with + // highest priority + int highestPriority = -1; + ICommandLauncherFactory bestLauncherFactory = null; + for (ICommandLauncherFactory factory : factories) { + if (factory instanceof ICommandLauncherFactory2) { + ICommandLauncher launcher = ((ICommandLauncherFactory2)factory).getCommandLauncher(config); + if (launcher != null) { + if (priorityMapping.get(factory) > highestPriority) { + bestLauncherFactory = factory; + } + } + } + } + return bestLauncherFactory; + } + + /** + * @since 6.5 + */ + public List processIncludePaths(ICBuildConfiguration config, List includePaths) { + ICommandLauncherFactory factory = getBestFactory(config); + if (factory != null && factory instanceof ICommandLauncherFactory2) { + return ((ICommandLauncherFactory2)factory).verifyIncludePaths(config, includePaths); + } + return includePaths; + } + public void setLanguageSettingEntries(IProject project, List entries) { ICommandLauncherFactory factory = getBestFactory(project); if (factory != null) { diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICommandLauncherFactory2.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICommandLauncherFactory2.java index 5b838e4e1c8..0b2f3f3866a 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICommandLauncherFactory2.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICommandLauncherFactory2.java @@ -10,6 +10,8 @@ *******************************************************************************/ package org.eclipse.cdt.core; +import java.util.List; + import org.eclipse.cdt.core.build.ICBuildConfiguration; /** @@ -27,5 +29,15 @@ public interface ICommandLauncherFactory2 { public default ICommandLauncher getCommandLauncher(ICBuildConfiguration cfg) { return null; } + + /** + * Process include paths and if necessary copy header files as needed. + * @param cfg - ICBuildConfiguration to process includes for + * @param includes List of include paths to process + * @return processed List of include paths + */ + public default List verifyIncludePaths(ICBuildConfiguration cfg, List includes) { + return includes; + } } diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/CBuildConfiguration.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/CBuildConfiguration.java index d9496b315b2..11344bafcce 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/CBuildConfiguration.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/CBuildConfiguration.java @@ -877,6 +877,14 @@ public abstract class CBuildConfiguration extends PlatformObject return false; } } + + /** + * @since 6.5 + */ + @Override + public void refreshScannerInfo() throws CoreException { + // do nothing by default + } @Override public void shutdown() { diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/ICBuildConfiguration.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/ICBuildConfiguration.java index b53a01e434d..91d7823815e 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/ICBuildConfiguration.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/ICBuildConfiguration.java @@ -124,6 +124,13 @@ public interface ICBuildConfiguration extends IAdaptable, IScannerInfoProvider { * @throws CoreException */ void clean(IConsole console, IProgressMonitor monitor) throws CoreException; + + /** + * Refresh the Scanner info + * + * @since 6.5 + */ + void refreshScannerInfo() throws CoreException; /** * The binaries produced by the build. diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/launch/CoreBuildLaunchBarTracker.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/launch/CoreBuildLaunchBarTracker.java index 18d30b98639..3edd04fd939 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/launch/CoreBuildLaunchBarTracker.java +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/launch/CoreBuildLaunchBarTracker.java @@ -93,7 +93,7 @@ public class CoreBuildLaunchBarTracker implements ILaunchBarListener { protected IStatus run(IProgressMonitor monitor) { try { Map properties = new HashMap<>(); - properties.putAll(target.getAttributes()); + properties.putAll(lastTarget.getAttributes()); Collection tcs = toolChainManager.getToolChainsMatching(properties); if (!tcs.isEmpty()) { ICBuildConfiguration buildConfig = null; @@ -130,6 +130,8 @@ public class CoreBuildLaunchBarTracker implements ILaunchBarListener { IProjectDescription desc = finalProject.getDescription(); desc.setActiveBuildConfig(buildConfig.getBuildConfiguration().getName()); finalProject.setDescription(desc, monitor); + // build config has changed so Scanner Info may change too which would affect indexing + buildConfig.refreshScannerInfo(); } } diff --git a/launch/org.eclipse.cdt.docker.launcher/META-INF/MANIFEST.MF b/launch/org.eclipse.cdt.docker.launcher/META-INF/MANIFEST.MF index 5570d05b4b3..975d2ff645a 100644 --- a/launch/org.eclipse.cdt.docker.launcher/META-INF/MANIFEST.MF +++ b/launch/org.eclipse.cdt.docker.launcher/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Plugin.name Bundle-SymbolicName: org.eclipse.cdt.docker.launcher;singleton:=true -Bundle-Version: 1.1.1.qualifier +Bundle-Version: 1.2.0.qualifier Bundle-Activator: org.eclipse.cdt.docker.launcher.DockerLaunchUIPlugin Bundle-Vendor: %Plugin.vendor Bundle-Localization: plugin @@ -27,7 +27,9 @@ Require-Bundle: org.eclipse.ui, org.eclipse.core.databinding.beans, org.eclipse.jface.databinding, org.eclipse.core.databinding;bundle-version="1.6.0", - org.eclipse.core.databinding.property;bundle-version="1.6.0" + org.eclipse.core.databinding.property;bundle-version="1.6.0", + org.eclipse.launchbar.ui;bundle-version="2.2.0", + com.google.gson Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-ActivationPolicy: lazy Export-Package: org.eclipse.cdt.docker.launcher, diff --git a/launch/org.eclipse.cdt.docker.launcher/plugin.properties b/launch/org.eclipse.cdt.docker.launcher/plugin.properties index 245288bb62e..038134a6414 100644 --- a/launch/org.eclipse.cdt.docker.launcher/plugin.properties +++ b/launch/org.eclipse.cdt.docker.launcher/plugin.properties @@ -22,3 +22,4 @@ Container.settings=Container Settings ContainerBuild.property.enablement=Container Build Enablement ContainerBuild.property.connection=Container Build Connection ContainerBuild.property.image=Container Build Image +ContainerTarget.name=Container Target diff --git a/launch/org.eclipse.cdt.docker.launcher/plugin.xml b/launch/org.eclipse.cdt.docker.launcher/plugin.xml index a9c3f67e105..0323cb81380 100644 --- a/launch/org.eclipse.cdt.docker.launcher/plugin.xml +++ b/launch/org.eclipse.cdt.docker.launcher/plugin.xml @@ -113,5 +113,47 @@ weight="020"> - + + + + + + + + + + + + + + + + + + + + + + diff --git a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/docker/launcher/ContainerCommandLauncher.java b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/docker/launcher/ContainerCommandLauncher.java index 003ae70cbda..53613f74c7d 100644 --- a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/docker/launcher/ContainerCommandLauncher.java +++ b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/docker/launcher/ContainerCommandLauncher.java @@ -13,6 +13,7 @@ import java.util.Properties; import org.eclipse.cdt.core.ICommandLauncher; import org.eclipse.cdt.core.build.ICBuildCommandLauncher; import org.eclipse.cdt.core.build.ICBuildConfiguration; +import org.eclipse.cdt.core.build.IToolChain; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.internal.core.ProcessClosure; @@ -88,6 +89,13 @@ public class ContainerCommandLauncher @Override public void setBuildConfiguration(ICBuildConfiguration config) { this.fBuildConfig = config; + if (fProject == null) { + try { + fProject = config.getBuildConfiguration().getProject(); + } catch (CoreException e) { + // ignore + } + } } @Override @@ -135,6 +143,16 @@ public class ContainerCommandLauncher return null; } + private boolean isSystemDir(IPath p) { + String firstSegment = p.segment(0); + if (firstSegment.equals("usr") || firstSegment.equals("opt") //$NON-NLS-1$ //$NON-NLS-2$ + || firstSegment.equals("bin") || firstSegment.equals("etc") //$NON-NLS-1$ //$NON-NLS-2$ + || firstSegment.equals("sbin")) { //$NON-NLS-1$ + return true; + } + return false; + } + @Override public Process execute(IPath commandPath, String[] args, String[] env, IPath workingDirectory, IProgressMonitor monitor) @@ -157,21 +175,21 @@ public class ContainerCommandLauncher ArrayList commandSegments = new ArrayList<>(); - StringBuilder b = new StringBuilder(); + List cmdList = new ArrayList<>(); + String commandString = commandPath.toPortableString(); if (commandPath.getDevice() != null) { commandString = "/" + commandString.replace(':', '/'); //$NON-NLS-1$ } - b.append(commandString); + cmdList.add(commandString); commandSegments.add(commandString); for (String arg : args) { - b.append(" "); //$NON-NLS-1$ String realArg = VariablesPlugin.getDefault() .getStringVariableManager().performStringSubstitution(arg); if (Platform.getOS().equals(Platform.OS_WIN32)) { // check if file exists and if so, add an additional directory IPath p = new Path(realArg); - if (p.isValidPath(realArg) && p.getDevice() != null) { + if (p.isValidPath(realArg) && p.getDevice() != null && !isSystemDir(p)) { File f = p.toFile(); String modifiedArg = realArg; // if the directory of the arg as a file exists, we mount it @@ -192,7 +210,7 @@ public class ContainerCommandLauncher // check if file directory exists and if so, add an additional // directory IPath p = new Path(realArg); - if (p.isValidPath(realArg)) { + if (p.isValidPath(realArg) && !isSystemDir(p)) { File f = p.toFile(); if (f.isFile()) { f = f.getParentFile(); @@ -202,19 +220,12 @@ public class ContainerCommandLauncher } } } - b.append(realArg); + cmdList.add(realArg); commandSegments.add(realArg); } commandArgs = commandSegments.toArray(new String[0]); - String commandDir = commandPath.removeLastSegments(1).toString(); - if (commandDir.isEmpty()) { - commandDir = null; - } else if (commandPath.getDevice() != null) { - commandDir = "/" + commandDir.replace(':', '/'); //$NON-NLS-1$ - } - IProject[] referencedProjects = fProject.getReferencedProjects(); for (IProject referencedProject : referencedProjects) { String referencedProjectPath = referencedProject.getLocation() @@ -227,8 +238,6 @@ public class ContainerCommandLauncher .add(referencedProjectPath); } - String command = b.toString(); - String workingDir = workingDirectory.makeAbsolute().toPortableString(); if (workingDirectory.toPortableString().equals(".")) { //$NON-NLS-1$ workingDir = "/tmp"; //$NON-NLS-1$ @@ -255,9 +264,12 @@ public class ContainerCommandLauncher String connectionName = null; String imageName = null; if (buildCfg != null) { - selectedVolumeString = buildCfg.getProperty(SELECTED_VOLUMES_ID); - connectionName = buildCfg.getProperty(CONNECTION_ID); - imageName = buildCfg.getProperty(IMAGE_ID); + IToolChain toolChain = buildCfg.getToolChain(); + selectedVolumeString = toolChain.getProperty(SELECTED_VOLUMES_ID); + connectionName = toolChain + .getProperty(IContainerLaunchTarget.ATTR_CONNECTION_URI); + imageName = toolChain + .getProperty(IContainerLaunchTarget.ATTR_IMAGE_ID); } else { ICConfigurationDescription cfgd = CoreModel.getDefault() .getProjectDescription(fProject).getActiveConfiguration(); @@ -301,8 +313,7 @@ public class ContainerCommandLauncher fProcess = launcher.runCommand(connectionName, imageName, fProject, this, - command, - commandDir, + cmdList, workingDir, additionalDirs, origEnv, fEnvironment, supportStdin, privilegedMode, diff --git a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/docker/launcher/ContainerCommandLauncherFactory.java b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/docker/launcher/ContainerCommandLauncherFactory.java index 3589d6c6467..369460f1588 100644 --- a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/docker/launcher/ContainerCommandLauncherFactory.java +++ b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/docker/launcher/ContainerCommandLauncherFactory.java @@ -16,13 +16,13 @@ import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.Set; import org.eclipse.cdt.core.ICommandLauncher; import org.eclipse.cdt.core.ICommandLauncherFactory; import org.eclipse.cdt.core.ICommandLauncherFactory2; import org.eclipse.cdt.core.build.ICBuildConfiguration; +import org.eclipse.cdt.core.build.IToolChain; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.settings.model.CIncludePathEntry; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; @@ -33,6 +33,7 @@ import org.eclipse.cdt.managedbuilder.buildproperties.IOptionalBuildProperties; import org.eclipse.cdt.managedbuilder.core.IConfiguration; import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Platform; import org.eclipse.linuxtools.docker.ui.launch.ContainerLauncher; @@ -98,20 +99,18 @@ public class ContainerCommandLauncherFactory @Override public ICommandLauncher getCommandLauncher(ICBuildConfiguration cfgd) { - // check if container build enablement has been checked - Map props = cfgd.getProperties(); - if (props != null) { - String enablementProperty = props - .get(ContainerCommandLauncher.CONTAINER_BUILD_ENABLED); - if (enablementProperty != null) { - boolean enableContainer = Boolean - .parseBoolean(enablementProperty); - // enablement has occurred, we can return a - // ContainerCommandLauncher - if (enableContainer) { + // check if container linux os is set + IToolChain toolchain; + try { + toolchain = cfgd.getToolChain(); + if (toolchain != null) { + if (ContainerTargetTypeProvider.CONTAINER_LINUX + .equals(toolchain.getProperty(IToolChain.ATTR_OS))) { return new ContainerCommandLauncher(); } } + } catch (CoreException e) { + DockerLaunchUIPlugin.log(e); } return null; } @@ -213,6 +212,112 @@ public class ContainerCommandLauncherFactory } + /** + * @since 1.2 + */ + @Override + public List verifyIncludePaths(ICBuildConfiguration cfgd, List includePaths) { + IToolChain toolchain = null; + boolean isContainerEnabled = false; + try { + toolchain = cfgd.getToolChain(); + if (toolchain != null) { + if (ContainerTargetTypeProvider.CONTAINER_LINUX + .equals(toolchain.getProperty(IToolChain.ATTR_OS))) { + isContainerEnabled = true; + } + } + } catch (CoreException e) { + DockerLaunchUIPlugin.log(e); + } + + if (isContainerEnabled) { + String connectionName = toolchain + .getProperty(IContainerLaunchTarget.ATTR_CONNECTION_URI); + String imageName = toolchain + .getProperty(IContainerLaunchTarget.ATTR_IMAGE_ID); + if (connectionName == null || connectionName.isEmpty() + || imageName == null || imageName.isEmpty()) { + DockerLaunchUIPlugin.logErrorMessage( + Messages.ContainerCommandLauncher_invalid_values); + return includePaths; + } + ContainerLauncher launcher = new ContainerLauncher(); + if (includePaths.size() > 0) { + // Create a directory to put the header files for + // the image. Use the connection name to form + // the directory name as the connection may be + // connected to a different repo using the same + // image name. + IPath pluginPath = Platform + .getStateLocation(Platform + .getBundle(DockerLaunchUIPlugin.PLUGIN_ID)) + .append("HEADERS"); //$NON-NLS-1$ + pluginPath.toFile().mkdir(); + pluginPath = pluginPath.append(getCleanName(connectionName)); + pluginPath.toFile().mkdir(); + // To allow the user to later manage the headers, store + // the + // real connection name in a file. + IPath connectionNamePath = pluginPath.append(".name"); //$NON-NLS-1$ + File f = connectionNamePath.toFile(); + try { + f.createNewFile(); + try (FileWriter writer = new FileWriter(f); + BufferedWriter bufferedWriter = new BufferedWriter( + writer);) { + bufferedWriter.write(connectionName); + bufferedWriter.newLine(); + } catch (IOException e) { + DockerLaunchUIPlugin.log(e); + return includePaths; + } + pluginPath = pluginPath.append(getCleanName(imageName)); + pluginPath.toFile().mkdir(); + // To allow the user to later manage the headers, + // store the + // real image name in a file. + IPath imageNamePath = pluginPath.append(".name"); //$NON-NLS-1$ + f = imageNamePath.toFile(); + f.createNewFile(); + try (FileWriter writer = new FileWriter(f); + BufferedWriter bufferedWriter = new BufferedWriter( + writer);) { + bufferedWriter.write(imageName); + bufferedWriter.newLine(); + } catch (IOException e) { + DockerLaunchUIPlugin.log(e); + return includePaths; + } + } catch (IOException e) { + DockerLaunchUIPlugin.log(e); + return includePaths; + } + IPath hostDir = pluginPath; + int status = launcher.fetchContainerDirsSync(connectionName, + imageName, includePaths, hostDir); + if (status == 0) { + Set copiedVolumes = launcher + .getCopiedVolumes(connectionName, imageName); + List newEntries = new ArrayList<>(); + + for (String path : includePaths) { + if (copiedVolumes.contains(path)) { + IPath newPath = hostDir.append(path); + String newEntry = newPath.toOSString(); + newEntries.add(newEntry); + } else { + newEntries.add(path); + } + } + return newEntries; + } + + } + } + return includePaths; + } + @Override public List verifyLanguageSettingEntries( IProject project, List entries) { diff --git a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/docker/launcher/ContainerTargetTypeProvider.java b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/docker/launcher/ContainerTargetTypeProvider.java new file mode 100644 index 00000000000..516f9396074 --- /dev/null +++ b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/docker/launcher/ContainerTargetTypeProvider.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2017, 2018 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat Inc. - modified for use with Docker Container launching + *******************************************************************************/ +package org.eclipse.cdt.docker.launcher; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.cdt.debug.core.CDebugCorePlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.Platform; +import org.eclipse.launchbar.core.ILaunchBarManager; +import org.eclipse.launchbar.core.target.ILaunchTarget; +import org.eclipse.launchbar.core.target.ILaunchTargetManager; +import org.eclipse.launchbar.core.target.ILaunchTargetProvider; +import org.eclipse.launchbar.core.target.ILaunchTargetWorkingCopy; +import org.eclipse.launchbar.core.target.TargetStatus; +import org.eclipse.linuxtools.docker.core.DockerConnectionManager; +import org.eclipse.linuxtools.docker.core.IDockerConnection; +import org.eclipse.linuxtools.docker.core.IDockerImage; + +/** + * @since 1.2 + * @author jjohnstn + * + */ +public class ContainerTargetTypeProvider implements ILaunchTargetProvider { + + public static final String TYPE_ID = "org.eclipse.cdt.docker.launcher.launchTargetType.container"; //$NON-NLS-1$ + public static final String CONTAINER_LINUX = "linux-container"; //$NON-NLS-1$ + + @Override + public void init(ILaunchTargetManager targetManager) { + ILaunchBarManager launchbarManager = CDebugCorePlugin + .getService(ILaunchBarManager.class); + ILaunchTarget defaultTarget = null; + try { + defaultTarget = launchbarManager.getActiveLaunchTarget(); + } catch (CoreException e) { + // ignore + } + IDockerConnection[] connections = DockerConnectionManager.getInstance() + .getConnections(); + Set imageNames = new HashSet<>(); + for (IDockerConnection connection : connections) { + List images = connection.getImages(); + for (IDockerImage image : images) { + if (!image.isDangling() && !image.isIntermediateImage()) { + String imageName = "[" //$NON-NLS-1$ + + image.repoTags().get(0).replace(':', '_') + "]"; //$NON-NLS-1$ + if (imageNames.contains(imageName)) { + imageName += "[" + connection.getName() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ + } + imageNames.add(imageName); + ILaunchTarget target = targetManager + .getLaunchTarget(TYPE_ID, imageName); + if (target == null) { + target = targetManager.addLaunchTarget(TYPE_ID, + imageName); + } + ILaunchTargetWorkingCopy wc = target.getWorkingCopy(); + wc.setAttribute(ILaunchTarget.ATTR_OS, CONTAINER_LINUX); + wc.setAttribute(ILaunchTarget.ATTR_ARCH, + Platform.getOSArch()); + wc.setAttribute(IContainerLaunchTarget.ATTR_CONNECTION_URI, + connection.getUri()); + wc.setAttribute(IContainerLaunchTarget.ATTR_IMAGE_ID, + image.repoTags().get(0)); + + wc.save(); + } + } + } + try { + launchbarManager.setActiveLaunchTarget(defaultTarget); + } catch (CoreException e) { + DockerLaunchUIPlugin.log(e); + } + } + + @Override + public TargetStatus getStatus(ILaunchTarget target) { + // Always OK + return TargetStatus.OK_STATUS; + } + +} diff --git a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/docker/launcher/IContainerLaunchTarget.java b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/docker/launcher/IContainerLaunchTarget.java new file mode 100644 index 00000000000..9413486c330 --- /dev/null +++ b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/docker/launcher/IContainerLaunchTarget.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2018 Red Hat Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat Inc. - initial contribution + *******************************************************************************/ +package org.eclipse.cdt.docker.launcher; + +/** + * @since 1.2 + * @author jjohnstn + * + */ +public interface IContainerLaunchTarget { + + // Container attributes + public static final String ATTR_CONNECTION_URI = "connection_uri"; //$NON-NLS-1$ + public static final String ATTR_IMAGE_ID = "image_id"; //$NON-NLS-1$ + +} diff --git a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ContainerLaunchConfigurationDelegate.java b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ContainerLaunchConfigurationDelegate.java index 2f600556861..f52cdea7a51 100644 --- a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ContainerLaunchConfigurationDelegate.java +++ b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ContainerLaunchConfigurationDelegate.java @@ -23,12 +23,22 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.build.ICBuildConfiguration; +import org.eclipse.cdt.core.build.ICBuildConfigurationManager; +import org.eclipse.cdt.core.build.IToolChain; +import org.eclipse.cdt.core.build.IToolChainManager; +import org.eclipse.cdt.debug.core.CDebugCorePlugin; import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.cdt.docker.launcher.ContainerTargetTypeProvider; import org.eclipse.cdt.docker.launcher.DockerLaunchUIPlugin; +import org.eclipse.cdt.docker.launcher.IContainerLaunchTarget; import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants; import org.eclipse.cdt.dsf.gdb.launching.GdbLaunchDelegate; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectDescription; +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.IProgressMonitor; @@ -42,6 +52,8 @@ import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.core.ILaunchManager; import org.eclipse.debug.core.model.ILaunchConfigurationDelegate; +import org.eclipse.launchbar.core.target.ILaunchTarget; +import org.eclipse.launchbar.core.target.ILaunchTargetManager; import org.eclipse.linuxtools.docker.core.Activator; import org.eclipse.linuxtools.docker.core.IDockerContainerInfo; import org.eclipse.linuxtools.docker.core.IDockerNetworkSettings; @@ -169,6 +181,14 @@ public class ContainerLaunchConfigurationDelegate extends GdbLaunchDelegate .getAttribute( ICDTLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, (String) null); + // if we don't have a working directory, the default is to use + // the project + if (workingDir == null && projectName != null) { + IProject project = ResourcesPlugin.getWorkspace().getRoot() + .getProject(projectName); + workingDir = project.getLocation().toOSString(); + } + if (workingDir != null) { IPath workingPath = new Path(workingDir); if (workingPath.getDevice() != null) { @@ -258,6 +278,13 @@ public class ContainerLaunchConfigurationDelegate extends GdbLaunchDelegate .getAttribute( ICDTLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, (String) null); + // if we don't have a working directory, the default is to use + // the project + if (workingDir == null && projectName != null) { + IProject project = ResourcesPlugin.getWorkspace().getRoot() + .getProject(projectName); + workingDir = project.getLocation().toOSString(); + } if (workingDir != null) { IPath workingPath = new Path(workingDir); if (workingPath.getDevice() != null) { @@ -492,6 +519,122 @@ public class ContainerLaunchConfigurationDelegate extends GdbLaunchDelegate return inputString.replaceAll(" ", "\\\\ "); //$NON-NLS-1$ //$NON-NLS-2$ } + public static IProject getProject(ILaunchConfiguration configuration) + throws CoreException { + // TODO - make sure this is really the correct project + return configuration.getMappedResources()[0].getProject(); + } + + /** + * @since 1.2 + */ + protected ICBuildConfigurationManager configManager = CDebugCorePlugin + .getService(ICBuildConfigurationManager.class); + /** + * @since 1.2 + */ + protected IToolChainManager toolChainManager = CDebugCorePlugin + .getService(IToolChainManager.class); + + /* + * @since 1.2 + */ + protected ICBuildConfiguration getBuildConfiguration( + ILaunchConfiguration configuration, String mode, + ILaunchTarget target, IProgressMonitor monitor) + throws CoreException { + IProject project = getProject(configuration); + String toolchainId = configuration + .getAttribute(ICBuildConfiguration.TOOLCHAIN_ID, (String) null); + if (toolchainId != null) { + String providerId = configuration + .getAttribute(ICBuildConfiguration.TOOLCHAIN_TYPE, ""); //$NON-NLS-1$ + IToolChain toolchain = toolChainManager.getToolChain(providerId, + toolchainId); + if (toolchain != null) { + return configManager.getBuildConfiguration(project, toolchain, + mode, monitor); + } + } + + // Pick the first one that matches + Map properties = new HashMap<>(); + properties.putAll(target.getAttributes()); + for (IToolChain toolChain : toolChainManager + .getToolChainsMatching(properties)) { + ICBuildConfiguration buildConfig = configManager + .getBuildConfiguration(project, toolChain, mode, monitor); + if (buildConfig != null) { + return buildConfig; + } + } + + return null; + } + + @Override + public boolean buildForLaunch(ILaunchConfiguration configuration, + String mode, IProgressMonitor monitor) throws CoreException { + IProject project = getProject(configuration); + String name = configuration.getName(); + Pattern p = Pattern.compile(".*?\\[([^\\]]+)\\](.*)"); //$NON-NLS-1$ + Matcher m = p.matcher(name); + if (m.matches()) { + ILaunchTargetManager targetManager = CCorePlugin + .getService(ILaunchTargetManager.class); + ILaunchTarget target = null; + ILaunchTarget[] targets = targetManager.getLaunchTargetsOfType( + ContainerTargetTypeProvider.TYPE_ID); + for (ILaunchTarget t : targets) { + if (t.getAttribute(IContainerLaunchTarget.ATTR_IMAGE_ID, "") + .replaceAll(":", "_").equals(m.group(1))) { + target = t; + break; + } + } + if (target != null) { + ICBuildConfiguration cconfig = getBuildConfiguration( + configuration, mode, target, monitor); + if (cconfig != null) { + IProjectDescription desc = project.getDescription(); + desc.setActiveBuildConfig( + cconfig.getBuildConfiguration().getName()); + project.setDescription(desc, monitor); + } + } + } + + return super.buildForLaunch(configuration, mode, monitor); + } + + @Override + public boolean preLaunchCheck(ILaunchConfiguration config, String mode, + IProgressMonitor monitor) throws CoreException { + String projectName = config.getAttribute( + ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, + (String) null); + IProject project = null; + if (projectName == null) { + IResource[] resources = config.getMappedResources(); + if (resources != null && resources.length > 0 + && resources[0] instanceof IProject) { + project = (IProject) resources[0]; + } + ILaunchConfigurationWorkingCopy wc = config.getWorkingCopy(); + wc.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, + project.getName()); + wc.doSave(); + } else { + projectName = projectName.trim(); + if (!projectName.isEmpty()) { + project = ResourcesPlugin.getWorkspace().getRoot() + .getProject(projectName); + } + } + + return super.preLaunchCheck(config, mode, monitor); + } + @Override protected String getPluginID() { return DockerLaunchUIPlugin.PLUGIN_ID; diff --git a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/LaunchShortcut.java b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/LaunchShortcut.java index 255a37258af..2f9eeac0f2e 100644 --- a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/LaunchShortcut.java +++ b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/LaunchShortcut.java @@ -15,6 +15,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import org.eclipse.cdt.core.build.ICBuildConfiguration; +import org.eclipse.cdt.core.build.IToolChain; import org.eclipse.cdt.core.model.CModelException; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.IBinary; @@ -24,6 +26,7 @@ import org.eclipse.cdt.debug.core.CDebugUtils; import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; import org.eclipse.cdt.docker.launcher.ContainerCommandLauncher; import org.eclipse.cdt.docker.launcher.DockerLaunchUIPlugin; +import org.eclipse.cdt.docker.launcher.IContainerLaunchTarget; import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants; import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants; import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin; @@ -31,6 +34,7 @@ import org.eclipse.cdt.managedbuilder.buildproperties.IOptionalBuildProperties; import org.eclipse.cdt.managedbuilder.core.IConfiguration; import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; import org.eclipse.cdt.ui.CElementLabelProvider; +import org.eclipse.core.resources.IBuildConfiguration; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; @@ -260,46 +264,63 @@ public class LaunchShortcut implements ILaunchShortcut { ILaunchConfigurationType configType = getLaunchConfigType(); List candidateConfigs = Collections.emptyList(); IProject project = bin.getCProject().getProject(); - ICConfigurationDescription cfgd = CoreModel.getDefault() - .getProjectDescription(project).getActiveConfiguration(); String connectionUri = null; String imageName = null; - if (cfgd != null) { - IConfiguration cfg = ManagedBuildManager - .getConfigurationForDescription(cfgd); - if (cfg != null) { - IOptionalBuildProperties props = cfg - .getOptionalBuildProperties(); - String containerBuild = props.getProperty( - ContainerCommandLauncher.CONTAINER_BUILD_ENABLED); - if (containerBuild != null) { - boolean containerBuildEnabled = Boolean - .parseBoolean(containerBuild); - if (containerBuildEnabled) { - connectionUri = props.getProperty( - ContainerCommandLauncher.CONNECTION_ID); - imageName = props - .getProperty(ContainerCommandLauncher.IMAGE_ID); - } - } else { - IDockerConnection[] connections = DockerConnectionManager - .getInstance().getConnections(); - if (connections != null && connections.length > 0) { - connectionUri = connections[0].getUri(); - Preferences prefs = InstanceScope.INSTANCE - .getNode(DockerLaunchUIPlugin.PLUGIN_ID); - imageName = prefs.get(PreferenceConstants.DEFAULT_IMAGE, - null); - if (imageName == null) { - List images = connections[0] - .getImages(); - if (images != null && images.size() > 0) - imageName = images.get(0).repoTags().get(0); + ICBuildConfiguration cbcfg = null; + try { + IBuildConfiguration buildConfig = project.getActiveBuildConfig(); + cbcfg = buildConfig.getAdapter(ICBuildConfiguration.class); + if (cbcfg != null) { + IToolChain toolChain = cbcfg.getToolChain(); + connectionUri = toolChain.getProperty( + IContainerLaunchTarget.ATTR_CONNECTION_URI); + imageName = toolChain + .getProperty(IContainerLaunchTarget.ATTR_IMAGE_ID); + } + } catch (CoreException e1) { + // do nothing + } + if (cbcfg == null) { + ICConfigurationDescription cfgd = CoreModel.getDefault() + .getProjectDescription(project).getActiveConfiguration(); + if (cfgd != null) { + IConfiguration cfg = ManagedBuildManager + .getConfigurationForDescription(cfgd); + if (cfg != null) { + IOptionalBuildProperties props = cfg + .getOptionalBuildProperties(); + String containerBuild = props.getProperty( + ContainerCommandLauncher.CONTAINER_BUILD_ENABLED); + if (containerBuild != null) { + boolean containerBuildEnabled = Boolean + .parseBoolean(containerBuild); + if (containerBuildEnabled) { + connectionUri = props.getProperty( + ContainerCommandLauncher.CONNECTION_ID); + imageName = props.getProperty( + ContainerCommandLauncher.IMAGE_ID); } } } } } + + if (connectionUri == null) { + IDockerConnection[] connections = DockerConnectionManager + .getInstance().getConnections(); + if (connections != null && connections.length > 0) { + connectionUri = connections[0].getUri(); + Preferences prefs = InstanceScope.INSTANCE + .getNode(DockerLaunchUIPlugin.PLUGIN_ID); + imageName = prefs.get(PreferenceConstants.DEFAULT_IMAGE, null); + if (imageName == null) { + List images = connections[0].getImages(); + if (images != null && images.size() > 0) + imageName = images.get(0).repoTags().get(0); + } + } + } + try { ILaunchConfiguration[] configs = DebugPlugin.getDefault() .getLaunchManager().getLaunchConfigurations(configType); @@ -308,23 +329,34 @@ public class LaunchShortcut implements ILaunchShortcut { IPath programPath = CDebugUtils.getProgramPath(config); String projectName = CDebugUtils.getProjectName(config); IPath binPath = bin.getResource().getProjectRelativePath(); - if (programPath != null && programPath.equals(binPath)) { - if (projectName != null - && projectName.equals(bin.getCProject() - .getProject().getName())) { - // if we have an active configuration with container - // build properties, make sure they match, otherwise - // add the launch config as a candidate - if (connectionUri != null - && connectionUri.equals(config.getAttribute( - ILaunchConstants.ATTR_CONNECTION_URI, - (String) null))) { - if (imageName != null && imageName.equals(config - .getAttribute(ILaunchConstants.ATTR_IMAGE, + if (projectName != null && projectName + .equals(bin.getCProject().getProject().getName())) { + if (programPath != null) { + if (programPath.equals(binPath)) { + // if we have an active configuration with container + // build properties, make sure they match, otherwise + // add the launch config as a candidate + if (connectionUri != null + && connectionUri.equals(config.getAttribute( + ILaunchConstants.ATTR_CONNECTION_URI, (String) null))) { - candidateConfigs.add(config); + if (imageName != null + && imageName.equals(config.getAttribute( + ILaunchConstants.ATTR_IMAGE, + (String) null))) { + candidateConfigs.add(config); + } } } + } else if (cbcfg != null && candidateConfigs.isEmpty()) { + ILaunchConfigurationWorkingCopy wc = config + .getWorkingCopy(); + populateLaunchConfiguration(wc, mode, bin, + projectName, + connectionUri, imageName); + wc.doSave(); + candidateConfigs.add(config); + break; } } } @@ -353,6 +385,59 @@ public class LaunchShortcut implements ILaunchShortcut { return configuration; } + private void populateLaunchConfiguration(ILaunchConfigurationWorkingCopy wc, + String mode, IBinary bin, String projectName, String connectionUri, + String imageName) { + // DSF settings...use GdbUIPlugin preference store for defaults + IPreferenceStore preferenceStore = GdbUIPlugin.getDefault() + .getPreferenceStore(); + wc.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUG_NAME, + preferenceStore.getString( + IGdbDebugPreferenceConstants.PREF_DEFAULT_GDB_COMMAND)); + wc.setAttribute(IGDBLaunchConfigurationConstants.ATTR_GDB_INIT, + preferenceStore.getString( + IGdbDebugPreferenceConstants.PREF_DEFAULT_GDB_INIT)); + wc.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP, + preferenceStore.getBoolean( + IGdbDebugPreferenceConstants.PREF_DEFAULT_NON_STOP)); + wc.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REVERSE, + IGDBLaunchConfigurationConstants.DEBUGGER_REVERSE_DEFAULT); + wc.setAttribute( + IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND, + IGDBLaunchConfigurationConstants.DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND_DEFAULT); + wc.setAttribute( + IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_DEBUG_ON_FORK, + IGDBLaunchConfigurationConstants.DEBUGGER_DEBUG_ON_FORK_DEFAULT); + wc.setAttribute( + IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_TRACEPOINT_MODE, + IGDBLaunchConfigurationConstants.DEBUGGER_TRACEPOINT_MODE_DEFAULT); + + wc.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, + bin.getResource().getProjectRelativePath().toString()); + wc.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, + projectName); + wc.setMappedResources(new IResource[] { bin.getResource(), + bin.getResource().getProject() }); + wc.setAttribute(ICDTLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, + (String) null); // default is the project directory + + Preferences prefs = InstanceScope.INSTANCE + .getNode(DockerLaunchUIPlugin.PLUGIN_ID); + + Boolean keepPref = prefs.getBoolean( + PreferenceConstants.KEEP_CONTAINER_AFTER_LAUNCH, false); + wc.setAttribute(ILaunchConstants.ATTR_KEEP_AFTER_LAUNCH, keepPref); + + // For Debug mode we need to set gdbserver info as well + if (mode.equals(ILaunchManager.DEBUG_MODE)) { + wc.setAttribute(ILaunchConstants.ATTR_GDBSERVER_COMMAND, + "gdbserver"); //$NON-NLS-1$ + wc.setAttribute(ILaunchConstants.ATTR_GDBSERVER_PORT, "2345"); //$NON-NLS-1$ + } + wc.setAttribute(ILaunchConstants.ATTR_CONNECTION_URI, connectionUri); + wc.setAttribute(ILaunchConstants.ATTR_IMAGE, imageName); + } + /** * Create a launch configuration based on a binary, and optionally save it * to the underlying resource. @@ -368,33 +453,45 @@ public class LaunchShortcut implements ILaunchShortcut { String mode, boolean save) { ILaunchConfiguration config = null; try { - String binaryPath = bin.getResource().getProjectRelativePath() - .toString(); - IProject project = bin.getResource().getProject(); - ICConfigurationDescription cfgd = CoreModel.getDefault() - .getProjectDescription(project).getActiveConfiguration(); - IConfiguration cfg = ManagedBuildManager - .getConfigurationForDescription(cfgd); - - IOptionalBuildProperties options = cfg.getOptionalBuildProperties(); boolean containerBuild = false; String connectionId = null; String imageName = null; + IBuildConfiguration buildConfig = project.getActiveBuildConfig(); + ICBuildConfiguration cbuildcfg = buildConfig + .getAdapter(ICBuildConfiguration.class); + if (cbuildcfg != null) { + IToolChain toolChain = cbuildcfg.getToolChain(); + connectionId = toolChain.getProperty( + IContainerLaunchTarget.ATTR_CONNECTION_URI); + imageName = toolChain + .getProperty(IContainerLaunchTarget.ATTR_IMAGE_ID); + } else { - if (options != null) { - String containerBuildString = options.getProperty( - ContainerCommandLauncher.CONTAINER_BUILD_ENABLED); - if (containerBuildString != null) { - containerBuild = Boolean.parseBoolean(options.getProperty( - ContainerCommandLauncher.CONTAINER_BUILD_ENABLED)); - } - if (containerBuild) { - connectionId = options.getProperty( - ContainerCommandLauncher.CONNECTION_ID); - imageName = options - .getProperty(ContainerCommandLauncher.IMAGE_ID); + ICConfigurationDescription cfgd = CoreModel.getDefault() + .getProjectDescription(project) + .getActiveConfiguration(); + IConfiguration cfg = ManagedBuildManager + .getConfigurationForDescription(cfgd); + + IOptionalBuildProperties options = cfg + .getOptionalBuildProperties(); + + if (options != null) { + String containerBuildString = options.getProperty( + ContainerCommandLauncher.CONTAINER_BUILD_ENABLED); + if (containerBuildString != null) { + containerBuild = Boolean + .parseBoolean(options.getProperty( + ContainerCommandLauncher.CONTAINER_BUILD_ENABLED)); + } + if (containerBuild) { + connectionId = options.getProperty( + ContainerCommandLauncher.CONNECTION_ID); + imageName = options + .getProperty(ContainerCommandLauncher.IMAGE_ID); + } } } @@ -406,41 +503,7 @@ public class LaunchShortcut implements ILaunchShortcut { ? ("[" + imageName + "]") //$NON-NLS-1$ //$NON-NLS-2$ : ""))); //$NON-NLS-1$ - // DSF settings...use GdbUIPlugin preference store for defaults - IPreferenceStore preferenceStore = GdbUIPlugin.getDefault() - .getPreferenceStore(); - wc.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUG_NAME, - preferenceStore.getString( - IGdbDebugPreferenceConstants.PREF_DEFAULT_GDB_COMMAND)); - wc.setAttribute(IGDBLaunchConfigurationConstants.ATTR_GDB_INIT, - preferenceStore.getString( - IGdbDebugPreferenceConstants.PREF_DEFAULT_GDB_INIT)); - wc.setAttribute( - IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP, - preferenceStore.getBoolean( - IGdbDebugPreferenceConstants.PREF_DEFAULT_NON_STOP)); - wc.setAttribute( - IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REVERSE, - IGDBLaunchConfigurationConstants.DEBUGGER_REVERSE_DEFAULT); - wc.setAttribute( - IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND, - IGDBLaunchConfigurationConstants.DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND_DEFAULT); - wc.setAttribute( - IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_DEBUG_ON_FORK, - IGDBLaunchConfigurationConstants.DEBUGGER_DEBUG_ON_FORK_DEFAULT); - wc.setAttribute( - IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_TRACEPOINT_MODE, - IGDBLaunchConfigurationConstants.DEBUGGER_TRACEPOINT_MODE_DEFAULT); - wc.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, - binaryPath); - wc.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, - bin.getCProject().getElementName()); - wc.setMappedResources(new IResource[] { bin.getResource(), - bin.getResource().getProject() }); - wc.setAttribute( - ICDTLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, - (String) null); Preferences prefs = InstanceScope.INSTANCE .getNode(DockerLaunchUIPlugin.PLUGIN_ID); @@ -480,8 +543,6 @@ public class LaunchShortcut implements ILaunchShortcut { return null; } - wc.setAttribute(ILaunchConstants.ATTR_CONNECTION_URI, - connection.getUri()); // use build image if one is specified, otherwise, see if a default // image is set in preferences, otherwise find first image in image @@ -513,18 +574,8 @@ public class LaunchShortcut implements ILaunchShortcut { return null; } - wc.setAttribute(ILaunchConstants.ATTR_IMAGE, (String) image); - - Boolean keepPref = prefs.getBoolean( - PreferenceConstants.KEEP_CONTAINER_AFTER_LAUNCH, false); - wc.setAttribute(ILaunchConstants.ATTR_KEEP_AFTER_LAUNCH, keepPref); - - // For Debug mode we need to set gdbserver info as well - if (mode.equals(ILaunchManager.DEBUG_MODE)) { - wc.setAttribute(ILaunchConstants.ATTR_GDBSERVER_COMMAND, - "gdbserver"); //$NON-NLS-1$ - wc.setAttribute(ILaunchConstants.ATTR_GDBSERVER_PORT, "2345"); //$NON-NLS-1$ - } + populateLaunchConfiguration(wc, mode, bin, project.getName(), + connection.getUri(), image); if (save) { config = wc.doSave(); @@ -532,7 +583,7 @@ public class LaunchShortcut implements ILaunchShortcut { config = wc; } } catch (CoreException e) { - e.printStackTrace(); + DockerLaunchUIPlugin.log(e); } return config; } diff --git a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/Messages.java b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/Messages.java index bb380e40c65..aa071ed6959 100644 --- a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/Messages.java +++ b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/Messages.java @@ -105,6 +105,8 @@ public class Messages extends NLS { public static String ContainerCommandLauncher_image_msg; public static String CommandLauncher_CommandCancelled; + public static String ContainerTarget_name; + public static String ContainerCommandLauncher_invalid_values; public static String Gdbserver_Settings_Remotetimeout_label; diff --git a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/messages.properties b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/messages.properties index 576419a814e..5b8e30e9590 100644 --- a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/messages.properties +++ b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/messages.properties @@ -45,6 +45,8 @@ ContainerPropertyTab_Enable_Msg=Build inside Docker Image ContainerPropertyTab_Run_Autotools_In_Container_Msg=Run all Autotools in Container ContainerPropertyTab_Run_Autotools_In_Container_Tooltip=Run Autotool commands in the Docker Container. This may cause inconsistencies between configurations sharing generated files. +ContainerTarget_name=Docker Container + HeaderPreferencePage_Connection_Label=Connection HeaderPreferencePage_Image_Label=Image HeaderPreferencePage_Remove_Label=Remove diff --git a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/ContainerGCCToolChain.java b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/ContainerGCCToolChain.java new file mode 100644 index 00000000000..ae828a9fd0b --- /dev/null +++ b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/ContainerGCCToolChain.java @@ -0,0 +1,606 @@ +/******************************************************************************* + * Copyright (c) 2015, 2017, 2018 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat Inc. - modified for use in Container build + *******************************************************************************/ +package org.eclipse.cdt.internal.docker.launcher.ui.launchbar; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.InvalidPathException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.CommandLauncherManager; +import org.eclipse.cdt.core.ICommandLauncher; +import org.eclipse.cdt.core.build.ICBuildConfiguration; +import org.eclipse.cdt.core.build.IToolChain; +import org.eclipse.cdt.core.build.IToolChainProvider; +import org.eclipse.cdt.core.dom.ast.gnu.c.GCCLanguage; +import org.eclipse.cdt.core.dom.ast.gnu.cpp.GPPLanguage; +import org.eclipse.cdt.core.envvar.IEnvironmentVariable; +import org.eclipse.cdt.core.model.ILanguage; +import org.eclipse.cdt.core.parser.ExtendedScannerInfo; +import org.eclipse.cdt.core.parser.IExtendedScannerInfo; +import org.eclipse.cdt.docker.launcher.ContainerCommandLauncher; +import org.eclipse.cdt.docker.launcher.ContainerTargetTypeProvider; +import org.eclipse.cdt.docker.launcher.DockerLaunchUIPlugin; +import org.eclipse.core.resources.IBuildConfiguration; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.linuxtools.docker.ui.Activator; + +/** + * The Container GCC toolchain. It represents a GCC that will run in a Docker + * Container. It can be overridden to change environment variable settings. + * + * @since 1.2 + */ +public class ContainerGCCToolChain extends PlatformObject implements IToolChain { + + public static final String TYPE_ID = "org.eclipse.cdt.docker.launcher.gcc"; //$NON-NLS-1$ + + private final IToolChainProvider provider; + private final String id; + private final Path path; + private final IEnvironmentVariable[] envVars; + private final Map properties = new HashMap<>(); + + private String cCommand; + private String cppCommand; + private String[] commands; + + + public ContainerGCCToolChain(String id, IToolChainProvider provider, + Map properties, + IEnvironmentVariable[] envVars) { + this.provider = provider; + this.path = new File("/usr/bin/gcc").toPath(); //$NON-NLS-1$ + + // We include arch in the id since a compiler can support multiple arches. + StringBuilder idBuilder = new StringBuilder("container-gcc-"); //$NON-NLS-1$ + idBuilder.append(properties.get(Platform.getOSArch())); + idBuilder.append('-'); + idBuilder.append(path.toString()); + this.id = id; + + this.properties.putAll(properties); + this.envVars = envVars; + } + + @Override + public String getTypeId() { + return TYPE_ID; + } + + public Path getPath() { + return path; + } + + @Override + public IToolChainProvider getProvider() { + return provider; + } + + @Override + public String getId() { + return id; + } + + @Override + public String getVersion() { + return ""; //$NON-NLS-1$ + } + + @Override + public String getName() { + StringBuilder name = new StringBuilder(); // $NON-NLS-1$ + String os = getProperty(ATTR_OS); + if (os != null) { + name.append(os); + name.append(' '); + } + + String arch = getProperty(ATTR_ARCH); + if (arch != null) { + name.append(arch); + name.append(' '); + } + + if (path != null) { + name.append(path.toString()); + } + + return name.toString(); + } + + @Override + public String getProperty(String key) { + String value = properties.get(key); + if (value != null) { + return value; + } + + switch (key) { + case ATTR_OS: + return ContainerTargetTypeProvider.CONTAINER_LINUX; + case ATTR_ARCH: + return Platform.getOSArch(); + } + + return null; + } + + public Map getProperties() { + return properties; + } + + @Override + public void setProperty(String key, String value) { + properties.put(key, value); + } + + @Override + public String getBinaryParserId() { + return CCorePlugin.PLUGIN_ID + ".ELF"; //$NON-NLS-1$ + } + + protected void addDiscoveryOptions(List command) { + command.add("-E"); //$NON-NLS-1$ + command.add("-P"); //$NON-NLS-1$ + command.add("-v"); //$NON-NLS-1$ + command.add("-dD"); //$NON-NLS-1$ + } + + @Override + public IExtendedScannerInfo getScannerInfo(IBuildConfiguration buildConfig, List commandStrings, + IExtendedScannerInfo baseScannerInfo, IResource resource, URI buildDirectoryURI) { + try { + Path buildDirectory = Paths.get(buildDirectoryURI); + + Path command = Paths.get(commandStrings.get(0)); + List commandLine = new ArrayList<>(); + if (command.isAbsolute()) { + commandLine.add(command.toString()); + } else { + commandLine.add(getCommandPath(command).toString()); + } + + if (baseScannerInfo != null) { + if (baseScannerInfo.getIncludePaths() != null) { + for (String includePath : baseScannerInfo.getIncludePaths()) { + commandLine.add("-I" + includePath); //$NON-NLS-1$ + } + } + + if (baseScannerInfo.getDefinedSymbols() != null) { + for (Map.Entry macro : baseScannerInfo.getDefinedSymbols().entrySet()) { + if (macro.getValue() != null && !macro.getValue().isEmpty()) { + commandLine.add("-D" + macro.getKey() + "=" + macro.getValue()); //$NON-NLS-1$ + } else { + commandLine.add("-D" + macro.getKey()); //$NON-NLS-1$ + } + } + } + } + + addDiscoveryOptions(commandLine); + commandLine.addAll(commandStrings.subList(1, commandStrings.size())); + + // Strip surrounding quotes from the args on Windows + if (Platform.OS_WIN32.equals(Platform.getOS())) { + for (int i = 0; i < commandLine.size(); i++) { + String arg = commandLine.get(i); + if (arg.startsWith("\"") && arg.endsWith("\"")) { //$NON-NLS-1$ //$NON-NLS-2$ + commandLine.set(i, arg.substring(1, arg.length() - 1)); + } + } + } + + // Change output to stdout + boolean haveOut = false; + for (int i = 0; i < commandLine.size() - 1; ++i) { + if (commandLine.get(i).equals("-o")) { //$NON-NLS-1$ + commandLine.set(i + 1, "-"); //$NON-NLS-1$ + haveOut = true; + break; + } + } + if (!haveOut) { + commandLine.add("-o"); //$NON-NLS-1$ + commandLine.add("-"); //$NON-NLS-1$ + } + + // Change source file to a tmp file (needs to be empty) + Path tmpFile = null; + for (int i = 1; i < commandLine.size(); ++i) { + String arg = commandLine.get(i); + if (!arg.startsWith("-")) { //$NON-NLS-1$ + Path filePath; + try { + filePath = buildDirectory.resolve(commandLine.get(i)).normalize(); + } catch (InvalidPathException e) { + continue; + } + IFile[] files = ResourcesPlugin.getWorkspace().getRoot().findFilesForLocationURI(filePath.toUri()); + if (files.length > 0 && files[0].exists()) { + // replace it with a temp file + Path parentPath = filePath.getParent(); + String extension = files[0].getFileExtension(); + if (extension == null) { + // Not sure if this is a reasonable choice when + // there's + // no extension + extension = ".cpp"; //$NON-NLS-1$ + } else { + extension = '.' + extension; + } + tmpFile = Files.createTempFile(parentPath, ".sc", extension); //$NON-NLS-1$ + commandLine.set(i, tmpFile.toString()); + } + } else if (arg.equals("-o")) { //$NON-NLS-1$ + // skip over the next arg + // TODO handle other args like this + i++; + } + } + if (tmpFile == null) { + // Have to assume there wasn't a source file. Add one in the + // resource's container + // TODO really? + IPath parentPath = resource instanceof IFile ? resource.getParent().getLocation() + : resource.getLocation(); + if (parentPath.toFile().exists()) { + tmpFile = Files.createTempFile(parentPath.toFile().toPath(), ".sc", ".cpp"); //$NON-NLS-1$ //$NON-NLS-2$ + commandLine.add(tmpFile.toString()); + } + } + + return getScannerInfo(buildConfig, commandLine, buildDirectory, tmpFile); + } catch (IOException e) { + Activator.log(e); + return null; + } + } + + @Override + public IExtendedScannerInfo getDefaultScannerInfo(IBuildConfiguration buildConfig, + IExtendedScannerInfo baseScannerInfo, ILanguage language, URI buildDirectoryURI) { + try { + String[] commands = getCompileCommands(language); + if (commands == null || commands.length == 0) { + // no default commands + return null; + } + + Path buildDirectory = Paths.get(buildDirectoryURI); + + // Pick the first one + Path command = Paths.get(commands[0]); + List commandLine = new ArrayList<>(); + if (command.isAbsolute()) { + commandLine.add(command.toString()); + } else { + commandLine.add(getCommandPath(command).toString()); + } + + if (baseScannerInfo != null) { + if (baseScannerInfo.getIncludePaths() != null) { + for (String includePath : baseScannerInfo.getIncludePaths()) { + commandLine.add("-I" + includePath); //$NON-NLS-1$ + } + } + + if (baseScannerInfo.getDefinedSymbols() != null) { + for (Map.Entry macro : baseScannerInfo.getDefinedSymbols().entrySet()) { + if (macro.getValue() != null && !macro.getValue().isEmpty()) { + commandLine.add("-D" + macro.getKey() + "=" + macro.getValue()); //$NON-NLS-1$ + } else { + commandLine.add("-D" + macro.getKey()); //$NON-NLS-1$ + } + } + } + } + + addDiscoveryOptions(commandLine); + + // output to stdout + commandLine.add("-o"); //$NON-NLS-1$ + commandLine.add("-"); //$NON-NLS-1$ + + // Source is an empty tmp file + String extension; + if (GPPLanguage.ID.equals(language.getId())) { + extension = ".cpp"; //$NON-NLS-1$ + } else if (GCCLanguage.ID.equals(language.getId())) { + extension = ".c"; //$NON-NLS-1$ + } else { + // In theory we shouldn't get here + return null; + } + + Path tmpFile = Files.createTempFile(buildDirectory, ".sc", extension); //$NON-NLS-1$ + commandLine.add(tmpFile.toString()); + + return getScannerInfo(buildConfig, commandLine, buildDirectory, tmpFile); + } catch (IOException e) { + Activator.log(e); + return null; + } + } + + private IExtendedScannerInfo getScannerInfo(IBuildConfiguration buildConfig, List commandLine, + Path buildDirectory, Path tmpFile) throws IOException { + Files.createDirectories(buildDirectory); + + // Startup the command + ContainerCommandLauncher commandLauncher = new ContainerCommandLauncher(); + ICBuildConfiguration cconfig = buildConfig + .getAdapter(ICBuildConfiguration.class); + commandLauncher.setBuildConfiguration(cconfig); + commandLauncher.setProject(buildConfig.getProject()); + // CCorePlugin.getDefault().getBuildEnvironmentManager().setEnvironment(processBuilder.environment(), + // buildConfig, true); + org.eclipse.core.runtime.IPath commandPath = new org.eclipse.core.runtime.Path( + commandLine.get(0)); + String[] args = commandLine.subList(1, commandLine.size()) + .toArray(new String[0]); + org.eclipse.core.runtime.IPath workingDirectory = new org.eclipse.core.runtime.Path( + buildDirectory.toString()); + + Process process; + try (ByteArrayOutputStream stdout = new ByteArrayOutputStream(); + ByteArrayOutputStream stderr = new ByteArrayOutputStream()) { + process = commandLauncher.execute(commandPath, args, new String[0], + workingDirectory, new NullProgressMonitor()); + if (process != null && commandLauncher.waitAndRead(stdout, stderr, + new NullProgressMonitor()) != ICommandLauncher.OK) { + String errMsg = commandLauncher.getErrorMessage(); + DockerLaunchUIPlugin.logErrorMessage(errMsg); + return null; + } + + // process.waitFor(); + + // Scan for the scanner info + Map symbols = new HashMap<>(); + List includePath = new ArrayList<>(); + Pattern definePattern = Pattern.compile("#define ([^\\s]*)\\s(.*)"); //$NON-NLS-1$ + boolean inIncludePaths = false; + + // concatenate stdout after stderr as stderr has the include paths + // and stdout has the defines + String[] outlines = stdout.toString(StandardCharsets.UTF_8.name()) + .split("\\r?\\n"); //$NON-NLS-1$ + String[] errlines = stderr.toString(StandardCharsets.UTF_8.name()) + .split("\\r?\\n"); //$NON-NLS-1$ + String[] lines = new String[errlines.length + outlines.length]; + System.arraycopy(errlines, 0, lines, 0, errlines.length); + System.arraycopy(outlines, 0, lines, errlines.length, + outlines.length); + + for (String line : lines) { + line = line.trim(); + if (inIncludePaths) { + if (line.equals("End of search list.")) { //$NON-NLS-1$ + inIncludePaths = false; + } else { + String include = line.trim(); + org.eclipse.core.runtime.IPath path = new org.eclipse.core.runtime.Path( + include); + if (!path.isAbsolute()) { + org.eclipse.core.runtime.IPath newPath = workingDirectory + .append(path); + include = newPath.makeAbsolute().toPortableString(); + } + includePath.add(include); + } + } else if (line.startsWith("#define ")) { //$NON-NLS-1$ + Matcher matcher = definePattern.matcher(line); + if (matcher.matches()) { + symbols.put(matcher.group(1), matcher.group(2)); + } + } else if (line.equals("#include <...> search starts here:")) { //$NON-NLS-1$ + inIncludePaths = true; + } + } + + // Process include paths for scanner info and point to any copied + // header directories + includePath = CommandLauncherManager.getInstance() + .processIncludePaths(cconfig, includePath); + + ExtendedScannerInfo info = new ExtendedScannerInfo(symbols, + includePath.toArray(new String[includePath.size()])); + return info; + } catch (CoreException e1) { + return null; + } finally { + Files.delete(tmpFile); + } + + } + + @Override + public String[] getErrorParserIds() { + return new String[] { "org.eclipse.cdt.core.GCCErrorParser", //$NON-NLS-1$ + "org.eclipse.cdt.core.GASErrorParser", //$NON-NLS-1$ + "org.eclipse.cdt.core.GLDErrorParser", //$NON-NLS-1$ + "org.eclipse.cdt.core.GmakeErrorParser", //$NON-NLS-1$ + "org.eclipse.cdt.core.CWDLocator" //$NON-NLS-1$ + }; + } + + @Override + public IEnvironmentVariable getVariable(String name) { + if (envVars != null) { + for (IEnvironmentVariable var : envVars) { + if (var.getName().equals(name)) { + return var; + } + } + } + return null; + } + + @Override + public IEnvironmentVariable[] getVariables() { + return envVars; + } + + @Override + public Path getCommandPath(Path command) { + if (command.isAbsolute()) { + return command; + } + + return new File("/usr/bin/" + command).toPath(); //$NON-NLS-1$ + } + + private void initCompileCommands() { + if (commands == null) { + cCommand = path.getFileName().toString(); + cppCommand = null; + if (cCommand.contains("gcc")) { //$NON-NLS-1$ + cppCommand = cCommand.replace("gcc", "g++"); //$NON-NLS-1$ //$NON-NLS-2$ + // Also recognize c++ as an alias for g++ + commands = new String[] { cCommand, cppCommand, cCommand.replace("gcc", "cc"), //$NON-NLS-1$ //$NON-NLS-2$ + cCommand.replace("gcc", "c++") }; //$NON-NLS-1$ //$NON-NLS-2$ + } else if (cCommand.contains("clang")) { //$NON-NLS-1$ + cppCommand = cCommand.replace("clang", "clang++"); //$NON-NLS-1$ //$NON-NLS-2$ + commands = new String[] { cCommand, cppCommand }; + } else if (cCommand.contains("emcc")) { //$NON-NLS-1$ + // TODO Hack for emscripten. Can we generalize? + cppCommand = cCommand.replace("emcc", "em++"); //$NON-NLS-1$ //$NON-NLS-2$ + commands = new String[] { cCommand, cppCommand }; + } else { + commands = new String[] { cCommand }; + } + } + } + + @Override + public String[] getCompileCommands() { + initCompileCommands(); + return commands; + } + + @Override + public String[] getCompileCommands(ILanguage language) { + initCompileCommands(); + if (GPPLanguage.ID.equals(language.getId())) { + return new String[] { cppCommand != null ? cppCommand : cCommand }; + } else if (GCCLanguage.ID.equals(language.getId())) { + return new String[] { cCommand }; + } else { + return new String[0]; + } + } + + @Override + public IResource[] getResourcesFromCommand(List cmd, URI buildDirectoryURI) { + // Start at the back looking for arguments + List resources = new ArrayList<>(); + IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); + for (int i = cmd.size() - 1; i >= 0; --i) { + String arg = cmd.get(i); + if (arg.startsWith("-")) { //$NON-NLS-1$ + // ran into an option, we're done. + break; + } + if (i > 1 && cmd.get(i - 1).equals("-o")) { //$NON-NLS-1$ + // this is an output file + --i; + continue; + } + try { + Path srcPath = Paths.get(arg); + URI uri; + if (srcPath.isAbsolute()) { + uri = srcPath.toUri(); + } else { + if (arg.startsWith("/") && Platform.getOS().equals(Platform.OS_WIN32)) { //$NON-NLS-1$ + String drive = srcPath.getName(0).toString(); + if (drive.length() == 1) { + srcPath = Paths.get(drive + ":\\").resolve(srcPath.subpath(1, srcPath.getNameCount())); //$NON-NLS-1$ + } + } + uri = Paths.get(buildDirectoryURI).resolve(srcPath).toUri().normalize(); + } + + for (IFile resource : root.findFilesForLocationURI(uri)) { + resources.add(resource); + } + } catch (IllegalArgumentException e) { + // Bad URI + continue; + } + } + + return resources.toArray(new IResource[resources.size()]); + } + + @Override + public List stripCommand(List command, IResource[] resources) { + List newCommand = new ArrayList<>(); + + for (int i = 0; i < command.size() - resources.length; ++i) { + String arg = command.get(i); + if (arg.startsWith("-o")) { //$NON-NLS-1$ + if (arg.equals("-o")) { //$NON-NLS-1$ + i++; + } + continue; + } + newCommand.add(arg); + } + + return newCommand; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ContainerGCCToolChain tc = (ContainerGCCToolChain) obj; + if (tc.id != this.id) + return false; + return true; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((id == null) ? 0 : id.hashCode()); + return result; + } + +} diff --git a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/ContainerGCCToolChainProvider.java b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/ContainerGCCToolChainProvider.java new file mode 100644 index 00000000000..b7392d20e01 --- /dev/null +++ b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/ContainerGCCToolChainProvider.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2018 Red Hat Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat Inc. - initial contribution + *******************************************************************************/ +package org.eclipse.cdt.internal.docker.launcher.ui.launchbar; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.cdt.core.build.IToolChainManager; +import org.eclipse.cdt.core.build.IToolChainProvider; +import org.eclipse.cdt.docker.launcher.ContainerTargetTypeProvider; +import org.eclipse.cdt.docker.launcher.IContainerLaunchTarget; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.Platform; +import org.eclipse.launchbar.core.target.ILaunchTarget; +import org.eclipse.linuxtools.docker.core.DockerConnectionManager; +import org.eclipse.linuxtools.docker.core.IDockerConnection; +import org.eclipse.linuxtools.docker.core.IDockerImage; + +/** + * + * @author jjohnstn + * + * @since 1.2 + * + */ +public class ContainerGCCToolChainProvider implements IToolChainProvider { + + public static final String PROVIDER_ID = "org.eclipse.cdt.docker.launcher.gcc.provider"; //$NON-NLS-1$ + public static final String CONTAINER_LINUX_CONFIG_ID = "linux-container-id"; //$NON-NLS-1$ + + @Override + public String getId() { + return PROVIDER_ID; + } + + @Override + public void init(IToolChainManager manager) throws CoreException { + IDockerConnection[] connections = DockerConnectionManager.getInstance() + .getConnections(); + for (IDockerConnection connection : connections) { + List images = connection.getImages(); + for (IDockerImage image : images) { + if (!image.isDangling() && !image.isIntermediateImage()) { + + Map properties = new HashMap<>(); + + properties.put(ILaunchTarget.ATTR_OS, + ContainerTargetTypeProvider.CONTAINER_LINUX); + properties.put(ILaunchTarget.ATTR_ARCH, + Platform.getOSArch()); + properties.put(IContainerLaunchTarget.ATTR_CONNECTION_URI, + connection.getUri()); + properties.put(IContainerLaunchTarget.ATTR_IMAGE_ID, + image.repoTags().get(0)); + // following can be used for naming build configurations + properties.put(CONTAINER_LINUX_CONFIG_ID, + image.repoTags().get(0).replace(':', '_')); + + ContainerGCCToolChain toolChain = new ContainerGCCToolChain( + "gcc-img-" + image.id().substring(0, 19), //$NON-NLS-1$ + this, properties, null); + + manager.addToolChain(toolChain); + } + } + } + } + +} diff --git a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/ContainerTargetLabelProvider.java b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/ContainerTargetLabelProvider.java new file mode 100644 index 00000000000..82c846e08d6 --- /dev/null +++ b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/ContainerTargetLabelProvider.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2017 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.internal.docker.launcher.ui.launchbar; + +import org.eclipse.cdt.debug.internal.ui.CDebugImages; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.launchbar.core.target.ILaunchTarget; +import org.eclipse.swt.graphics.Image; + +/** + * @author jjohnstn + * @since 1.2 + * + */ +public class ContainerTargetLabelProvider extends LabelProvider { + + @Override + public String getText(Object element) { + if (element instanceof ILaunchTarget) { + return ((ILaunchTarget) element).getId(); + } + return super.getText(element); + } + + @Override + public Image getImage(Object element) { + return CDebugImages.get(CDebugImages.IMG_OBJS_CDT_LOGO); + } + +} diff --git a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/CoreBuildContainerLaunchConfigProvider.java b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/CoreBuildContainerLaunchConfigProvider.java new file mode 100644 index 00000000000..6b51587372a --- /dev/null +++ b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/CoreBuildContainerLaunchConfigProvider.java @@ -0,0 +1,201 @@ +/******************************************************************************* + * Copyright (c) 2016 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.internal.docker.launcher.ui.launchbar; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.cdt.docker.launcher.ContainerTargetTypeProvider; +import org.eclipse.cdt.docker.launcher.IContainerLaunchTarget; +import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants; +import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants; +import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationType; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.launchbar.core.AbstractLaunchConfigProvider; +import org.eclipse.launchbar.core.ILaunchDescriptor; +import org.eclipse.launchbar.core.target.ILaunchTarget; + +/** + * @since 1.2 + * @author jjohnstn + * + */ +public class CoreBuildContainerLaunchConfigProvider extends AbstractLaunchConfigProvider { + + private static final String TYPE_ID = "org.eclipse.cdt.docker.launcher.launchConfigurationType"; //$NON-NLS-1$ + + private Map> configs = new HashMap<>(); + + @Override + public boolean supports(ILaunchDescriptor descriptor, ILaunchTarget target) throws CoreException { + return target != null && ContainerTargetTypeProvider.TYPE_ID + .equals(target.getTypeId()); + } + + @Override + public ILaunchConfigurationType getLaunchConfigurationType(ILaunchDescriptor descriptor, ILaunchTarget target) + throws CoreException { + return DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurationType(TYPE_ID); + } + + @Override + public ILaunchConfiguration getLaunchConfiguration(ILaunchDescriptor descriptor, ILaunchTarget target) + throws CoreException { + ILaunchConfiguration config = null; + IProject project = descriptor.getAdapter(IProject.class); + if (project != null) { + Map configMap = configs.get(project); + if (configMap == null) { + configMap = new HashMap<>(); + } + String connection = target.getAttribute( + IContainerLaunchTarget.ATTR_CONNECTION_URI, ""); //$NON-NLS-1$ + String imageId = target + .getAttribute(IContainerLaunchTarget.ATTR_IMAGE_ID, ""); //$NON-NLS-1$ + String imageName = connection + "-" + imageId; //$NON-NLS-1$ + config = configMap.get(imageName); + if (config == null) { + config = createLaunchConfiguration(descriptor, target); + // launch config added will get called below to add it to the + // configs map + } + } + return config; + } + + private String getImageName(ILaunchConfiguration config) + throws CoreException { + String connection = config + .getAttribute(IContainerLaunchTarget.ATTR_CONNECTION_URI, ""); //$NON-NLS-1$ + String image = config.getAttribute(IContainerLaunchTarget.ATTR_IMAGE_ID, + ""); //$NON-NLS-1$ + String imageName = connection + "-" + image; //$NON-NLS-1$ + + return imageName; + } + + @Override + protected void populateLaunchConfiguration(ILaunchDescriptor descriptor, ILaunchTarget target, + ILaunchConfigurationWorkingCopy wc) throws CoreException { + super.populateLaunchConfiguration(descriptor, target, wc); + + // Set the project and the connection + IProject project = descriptor.getAdapter(IProject.class); + wc.setAttribute( + ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, + project.getName()); + wc.setAttribute(IContainerLaunchTarget.ATTR_CONNECTION_URI, + target.getAttribute(IContainerLaunchTarget.ATTR_CONNECTION_URI, + null)); + wc.setAttribute(IContainerLaunchTarget.ATTR_IMAGE_ID, target + .getAttribute(IContainerLaunchTarget.ATTR_IMAGE_ID, null)); + + // DSF settings...use GdbUIPlugin preference store for defaults + IPreferenceStore preferenceStore = GdbUIPlugin.getDefault() + .getPreferenceStore(); + wc.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUG_NAME, + preferenceStore.getString( + IGdbDebugPreferenceConstants.PREF_DEFAULT_GDB_COMMAND)); + wc.setAttribute(IGDBLaunchConfigurationConstants.ATTR_GDB_INIT, + preferenceStore.getString( + IGdbDebugPreferenceConstants.PREF_DEFAULT_GDB_INIT)); + wc.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP, + preferenceStore.getBoolean( + IGdbDebugPreferenceConstants.PREF_DEFAULT_NON_STOP)); + wc.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REVERSE, + IGDBLaunchConfigurationConstants.DEBUGGER_REVERSE_DEFAULT); + wc.setAttribute( + IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND, + IGDBLaunchConfigurationConstants.DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND_DEFAULT); + wc.setAttribute( + IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_DEBUG_ON_FORK, + IGDBLaunchConfigurationConstants.DEBUGGER_DEBUG_ON_FORK_DEFAULT); + wc.setAttribute( + IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_TRACEPOINT_MODE, + IGDBLaunchConfigurationConstants.DEBUGGER_TRACEPOINT_MODE_DEFAULT); + wc.setAttribute(ICDTLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, + (String) null); // default is the project directory + + wc.setMappedResources(new IResource[] { project }); + } + + @Override + public boolean launchConfigurationAdded(ILaunchConfiguration configuration) throws CoreException { + if (ownsLaunchConfiguration(configuration)) { + IProject project = configuration.getMappedResources()[0].getProject(); + Map configMap = configs.get(project); + if (configMap == null) { + configMap = new HashMap<>(); + configs.put(project, configMap); + } + String imageName = getImageName(configuration); + if (!imageName.equals("-")) { //$NON-NLS-1$ + configMap.put(imageName, configuration); + } + return true; + } + return false; + } + + @Override + public boolean launchConfigurationRemoved(ILaunchConfiguration configuration) throws CoreException { + for (Entry> entry : configs + .entrySet()) { + for (Entry innerEntry : entry + .getValue().entrySet()) { + if (configuration.equals(innerEntry.getValue())) { + entry.getValue().remove(innerEntry.getKey()); + return true; + } + } + } + return false; + } + + @Override + public boolean launchConfigurationChanged(ILaunchConfiguration configuration) throws CoreException { + // if (ownsLaunchConfiguration(configuration)) { + // IProject project = configuration.getMappedResources()[0] + // .getProject(); + // Map configMap = configs.get(project); + // if (configMap == null) { + // configMap = new HashMap<>(); + // configs.put(project, configMap); + // } + // String imageName = getImageName(configuration); + // if (!imageName.isEmpty()) { + // configMap.put(imageName, configuration); + // } + // return true; + // } + return false; + } + + @Override + public void launchDescriptorRemoved(ILaunchDescriptor descriptor) throws CoreException { + IProject project = descriptor.getAdapter(IProject.class); + if (project != null) { + configs.remove(project); + } + } + + @Override + public void launchTargetRemoved(ILaunchTarget target) throws CoreException { + // nothing to do since the Local connection can't be removed + } + +} diff --git a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/CoreBuildContainerLaunchDescriptorType.java b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/CoreBuildContainerLaunchDescriptorType.java new file mode 100644 index 00000000000..2117d94e8ec --- /dev/null +++ b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/CoreBuildContainerLaunchDescriptorType.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2016 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.internal.docker.launcher.ui.launchbar; + +import org.eclipse.cdt.core.build.ICBuildConfigurationManager; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.launchbar.core.ILaunchDescriptor; +import org.eclipse.launchbar.core.ILaunchDescriptorType; +import org.eclipse.launchbar.core.ProjectLaunchDescriptor; +import org.eclipse.launchbar.core.internal.Activator; + +/** + * The launch descriptor type for launch objects built with the Core Build + * System. + * + * @since 1.2 + */ +public class CoreBuildContainerLaunchDescriptorType implements ILaunchDescriptorType { + + @Override + public ILaunchDescriptor getDescriptor(Object launchObject) throws CoreException { + if (launchObject instanceof IProject) { + // Make sure it's a new style build + IProject project = (IProject) launchObject; + if (Activator.getService(ICBuildConfigurationManager.class).supports(project)) { + return new ProjectLaunchDescriptor(this, project); + } + } + // TODO IBinary + return null; + } + +} diff --git a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/Messages.java b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/Messages.java new file mode 100644 index 00000000000..002e391f1c8 --- /dev/null +++ b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/Messages.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2018 Red Hat Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Red Hat Inc. - initial version + *******************************************************************************/ +package org.eclipse.cdt.internal.docker.launcher.ui.launchbar; + +import org.eclipse.osgi.util.NLS; + +/** + * @since 1.2 + * @author jjohnstn + * + */ +public class Messages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.cdt.internal.docker.launcher.ui.launchbar.messages"; //$NON-NLS-1$ + + public static String ContainerGCCToolChainProvider_Saving1; + public static String ContainerGCCToolChainProvider_Saving; + public static String ContainerGCCToolChainProvider_NotOurs; + public static String ContainerGCCToolChainProvider_Loading; + + public static String NewContainerTargetWizard_title; + public static String NewContainerTargetWizardPage_name; + public static String NewContainerTargetWizardPage_title; + public static String NewContainerTargetWizardPage_description; + public static String NewContainerTargetWizardPage_no_connections; + public static String NewContainerTargetWizardPage_no_images; + public static String NewContainerTargetWizardPage_connection; + public static String NewContainerTargetWizardPage_image; + + public static String EditContainerTargetWizard_title; + public static String EditContainerTargetWizardPage_title; + public static String EditContainerTargetWizardPage_description; + + + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } +} + diff --git a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/NewContainerTargetWizard.java b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/NewContainerTargetWizard.java new file mode 100644 index 00000000000..d2e00ece221 --- /dev/null +++ b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/NewContainerTargetWizard.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright (c) 2018 Red Hat Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat Inc. - initial contribution + *******************************************************************************/ +package org.eclipse.cdt.internal.docker.launcher.ui.launchbar; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.cdt.core.build.IToolChain; +import org.eclipse.cdt.core.build.IToolChainManager; +import org.eclipse.cdt.debug.core.CDebugCorePlugin; +import org.eclipse.cdt.debug.ui.CDebugUIPlugin; +import org.eclipse.cdt.docker.launcher.ContainerTargetTypeProvider; +import org.eclipse.cdt.docker.launcher.IContainerLaunchTarget; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.Platform; +import org.eclipse.launchbar.core.target.ILaunchTarget; +import org.eclipse.launchbar.core.target.ILaunchTargetManager; +import org.eclipse.launchbar.core.target.ILaunchTargetWorkingCopy; +import org.eclipse.launchbar.ui.internal.Activator; +import org.eclipse.launchbar.ui.target.LaunchTargetWizard; + +@SuppressWarnings("restriction") +/** + * @since 1.2 + * @author jjohnstn + * + */ +public class NewContainerTargetWizard extends LaunchTargetWizard { + + private NewContainerTargetWizardPage page; + protected IToolChainManager toolChainManager = CDebugCorePlugin + .getService(IToolChainManager.class); + + public NewContainerTargetWizard() { + if (getLaunchTarget() == null) { + setWindowTitle(Messages.NewContainerTargetWizard_title); + } else { + setWindowTitle(Messages.EditContainerTargetWizard_title); + } + } + + @Override + public void addPages() { + super.addPages(); + + page = new NewContainerTargetWizardPage(getLaunchTarget()); + addPage(page); + } + + @Override + public boolean performFinish() { + ILaunchTargetManager manager = CDebugUIPlugin + .getService(ILaunchTargetManager.class); + String typeId = ContainerTargetTypeProvider.TYPE_ID; + String id = page.getTargetName(); + + ILaunchTarget target = getLaunchTarget(); + if (target == null) { + target = manager.addLaunchTarget(typeId, id); + } + + ILaunchTargetWorkingCopy wc = target.getWorkingCopy(); + wc.setId(id); + wc.setAttribute(ILaunchTarget.ATTR_OS, Platform.getOS()); + wc.setAttribute(ILaunchTarget.ATTR_ARCH, + ContainerTargetTypeProvider.CONTAINER_LINUX); + wc.setAttribute(IContainerLaunchTarget.ATTR_CONNECTION_URI, + page.getConnectionURI()); + wc.setAttribute(IContainerLaunchTarget.ATTR_IMAGE_ID, + page.getImageId()); + wc.save(); + + // Pick the first one that matches + Map properties = new HashMap<>(); + properties.putAll(wc.getAttributes()); + Collection toolChains = Collections.emptyList(); + try { + toolChains = toolChainManager.getToolChainsMatching(properties); + } catch (CoreException e) { + // do nothing + } + + // if (toolChains.size() == 0) { + // // add new Container toolchain with attributes above + // ContainerToolChain toolChain = new ContainerToolChain(); + // toolChain.add(properties); + // } + + return true; + } + + @Override + public boolean canDelete() { + return true; + } + + @Override + public void performDelete() { + ILaunchTargetManager manager = Activator + .getService(ILaunchTargetManager.class); + ILaunchTarget target = getLaunchTarget(); + if (target != null) { + manager.removeLaunchTarget(getLaunchTarget()); + } + } + +} diff --git a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/NewContainerTargetWizardPage.java b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/NewContainerTargetWizardPage.java new file mode 100644 index 00000000000..d6c821a021a --- /dev/null +++ b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/NewContainerTargetWizardPage.java @@ -0,0 +1,309 @@ +/******************************************************************************* + * Copyright (c) 2018 Red Hat Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contibutors: + * Red Hat Inc. - initial implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.docker.launcher.ui.launchbar; + +import java.util.ArrayList; + +import org.eclipse.cdt.docker.launcher.IContainerLaunchTarget; +import org.eclipse.cdt.internal.docker.launcher.SWTImagesFactory; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.launchbar.core.target.ILaunchTarget; +import org.eclipse.linuxtools.docker.core.DockerConnectionManager; +import org.eclipse.linuxtools.docker.core.IDockerConnection; +import org.eclipse.linuxtools.docker.core.IDockerConnectionManagerListener; +import org.eclipse.linuxtools.docker.core.IDockerImage; +import org.eclipse.linuxtools.docker.core.IDockerImageListener; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.events.VerifyEvent; +import org.eclipse.swt.events.VerifyListener; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; + +/** + * @since 1.2 + * @author jjohnstn + * + */ +public class NewContainerTargetWizardPage extends WizardPage + implements IDockerImageListener, IDockerConnectionManagerListener { + + private final ILaunchTarget launchTarget; + + private Text nameText; + private Combo imageCombo; + private Combo connectionSelector; + private IDockerConnection connection; + private IDockerConnection[] connections; + private IDockerImageListener wizardPage; + private String imageName; + private String connectionName; + private String connectionUri = ""; + + + public NewContainerTargetWizardPage(ILaunchTarget launchTarget) { + super(NewContainerTargetWizardPage.class.getName()); + if (launchTarget == null) { + setTitle(Messages.NewContainerTargetWizardPage_title); + setDescription(Messages.NewContainerTargetWizardPage_description); + } else { + setTitle(Messages.EditContainerTargetWizardPage_title); + setDescription(Messages.EditContainerTargetWizardPage_description); + } + this.launchTarget = launchTarget; + this.wizardPage = this; + if (launchTarget != null) { + connectionUri = launchTarget.getAttribute( + IContainerLaunchTarget.ATTR_CONNECTION_URI, null); + imageName = launchTarget + .getAttribute(IContainerLaunchTarget.ATTR_IMAGE_ID, null); + } + } + + private ModifyListener connectionModifyListener = new ModifyListener() { + + @Override + public void modifyText(ModifyEvent e) { + int index = connectionSelector.getSelectionIndex(); + if (connection != null) + connection.removeImageListener(wizardPage); + connection = connections[index]; + connectionUri = connection.getUri(); + if (!connectionName.equals(connection.getName())) { + setErrorMessage(null); + imageName = null; + initializeImageCombo(); + setPageComplete(false); + } + connectionName = connection.getName(); + } + + }; + + @Override + public void createControl(Composite parent) { + Composite comp = new Composite(parent, SWT.NONE); + comp.setLayout(new GridLayout(2, false)); + + Label label = new Label(comp, SWT.NONE); + label.setText(Messages.NewContainerTargetWizardPage_name); + + nameText = new Text(comp, SWT.BORDER); + nameText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + if (launchTarget != null) { + nameText.setText(launchTarget.getId()); + nameText.setEnabled(false); + } + + label = new Label(comp, SWT.NONE); + label.setText(Messages.NewContainerTargetWizardPage_connection); + + connectionSelector = new Combo(comp, SWT.BORDER | SWT.READ_ONLY); + initializeConnectionSelector(); + connectionSelector.addModifyListener(connectionModifyListener); + // Following is a kludge so that on Linux the Combo is read-only but + // has a white background. + connectionSelector.addVerifyListener(new VerifyListener() { + @Override + public void verifyText(VerifyEvent e) { + e.doit = false; + } + }); + GridData gd = new GridData(); + gd.horizontalSpan = 2; + gd.horizontalIndent = 5; + connectionSelector.setLayoutData(gd); + + Label imageSelectorLabel = new Label(comp, SWT.NULL); + imageSelectorLabel.setText(Messages.NewContainerTargetWizardPage_image); + imageCombo = new Combo(comp, SWT.DROP_DOWN); + GridData gd2 = new GridData(); + gd2.horizontalSpan = 2; + gd2.horizontalIndent = 5; + imageCombo.setLayoutData(gd2); + + initializeImageCombo(); + + imageCombo.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + imageName = imageCombo.getText(); + setPageComplete(imageName != null && !imageName.isEmpty()); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + } + + }); + + setPageComplete(false); + setControl(comp); + } + + public String getTargetName() { + return nameText.getText().trim(); + } + + public String getConnectionURI() { + return connectionUri; + } + + public String getImageId() { + return imageName; + } + + @Override + public Image getImage() { + return SWTImagesFactory.get(SWTImagesFactory.IMG_CONTAINER); + } + + private void initializeConnectionSelector() { + int defaultIndex = -1; + connections = DockerConnectionManager.getInstance().getConnections(); + if (connections.length == 0) { + setErrorMessage( + Messages.NewContainerTargetWizardPage_no_connections); + return; + } + String[] connectionNames = new String[connections.length]; + for (int i = 0; i < connections.length; ++i) { + connectionNames[i] = connections[i].getName(); + if (connections[i].getUri().equals(connectionUri)) + defaultIndex = i; + } + if (defaultIndex < 0) { + defaultIndex = 0; + } + connectionSelector.setItems(connectionNames); + if (connections.length > 0) { + connectionSelector.setText(connectionNames[defaultIndex]); + connection = connections[defaultIndex]; + connectionName = connection.getName(); + connectionUri = connection.getUri(); + } + } + + private void initializeImageCombo() { + if (connection != null) { + java.util.List images = connection.getImages(); + if (images == null || images.size() == 0) { + setErrorMessage( + Messages.NewContainerTargetWizardPage_no_images); + return; + } + connection.removeImageListener(wizardPage); + ArrayList imageNames = new ArrayList(); + for (IDockerImage image : images) { + java.util.List tags = image.repoTags(); + if (tags != null) { + for (String tag : tags) { + if (!tag.equals(":")) //$NON-NLS-1$ + imageNames.add(tag); + } + } + } + imageCombo.setItems(imageNames.toArray(new String[0])); + if (imageName != null) + imageCombo.setText(imageName); + connection.addImageListener(wizardPage); + } + } + + @Override + public void changeEvent(IDockerConnection changedConnection, int type) { + String currUri = null; + int currIndex = 0; + setErrorMessage(null); + connections = DockerConnectionManager.getInstance().getConnections(); + if (connection != null) { + currUri = connection.getUri(); + currIndex = connectionSelector.getSelectionIndex(); + } + String[] connectionNames = new String[connections.length]; + int index = 0; + for (int i = 0; i < connections.length; ++i) { + connectionNames[i] = connections[i].getName(); + if (connections[i].getUri().equals(currUri)) + index = i; + } + if (type == IDockerConnectionManagerListener.RENAME_EVENT) { + index = currIndex; // no change in connection displayed + } + connectionSelector.removeModifyListener(connectionModifyListener); + connectionSelector.setItems(connectionNames); + if (connectionNames.length > 0) { + connectionSelector.setText(connectionNames[index]); + connection = connections[index]; + connectionUri = connection.getUri(); + java.util.List images = connection.getImages(); + if (images == null || images.size() == 0) { + setErrorMessage( + Messages.NewContainerTargetWizardPage_no_images); + } + } else { + setErrorMessage( + Messages.NewContainerTargetWizardPage_no_connections); + connection = null; + connectionUri = ""; + connectionSelector.setText(""); + } + connectionSelector.addModifyListener(connectionModifyListener); + } + + public void listChanged(IDockerConnection c, + java.util.List list) { + setErrorMessage(null); + final IDockerImage[] finalList = list.toArray(new IDockerImage[0]); + if (finalList.length == 0) { + setErrorMessage(Messages.NewContainerTargetWizardPage_no_images); + } + if (c.getName().equals(connection.getName())) { + Display.getDefault().syncExec(new Runnable() { + @Override + public void run() { + connection.removeImageListener(wizardPage); + ArrayList imageNames = new ArrayList(); + for (IDockerImage image : finalList) { + java.util.List tags = image.repoTags(); + if (tags != null) { + for (String tag : tags) { + imageNames.add(tag); + } + } + } + if (!imageCombo.isDisposed()) + imageCombo.setItems(imageNames.toArray(new String[0])); + connection.addImageListener(wizardPage); + } + + }); + } + } + + @Override + public void dispose() { + if (connection != null) + connection.removeImageListener(this); + super.dispose(); + } + +} diff --git a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/messages.properties b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/messages.properties new file mode 100644 index 00000000000..521d1242d76 --- /dev/null +++ b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ui/launchbar/messages.properties @@ -0,0 +1,28 @@ +################################################################################ +# Copyright (c) 2018 Red Hat Inc. and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Red Hat Inc. - initial implementation +################################################################################ +NewContainerTargetWizard_title=New Docker Container Target +NewContainerTargetWizardPage_name=Name: +NewContainerTargetWizardPage_image=Image: +NewContainerTargetWizardPage_title=Container Target +NewContainerTargetWizardPage_description=Enter name and properties for the target. +NewContainerTargetWizardPage_no_connections=No Docker connections are available +NewContainerTargetWizardPage_no_images=Docker connection has no pulled images +NewContainerTargetWizardPage_connection=Connection: + +EditContainerTargetWizard_title=Edit Docker Container Target +EditContainerTargetWizardPage_title=Container Target +EditContainerTargetWizardPage_description=Edit properties for the target. + +ContainerGCCToolChainProvider_Saving1=Saving Container toolchain file +ContainerGCCToolChainProvider_Saving=Saving Container toolchain file +ContainerGCCToolChainProvider_NotOurs=Not ours +ContainerGCCToolChainProvider_Loading=Loading Container toolchain file + +