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 3ab87a6dbdd..cae5dadc7e5 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 @@ -1,3 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2017, 2022 Red Hat Inc. and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + * Mathema - Refactor + *******************************************************************************/ package org.eclipse.cdt.docker.launcher; import java.io.File; @@ -9,6 +23,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.stream.Collectors; import org.eclipse.cdt.core.ICommandLauncher; import org.eclipse.cdt.core.build.ICBuildCommandLauncher; @@ -17,6 +32,7 @@ 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; +import org.eclipse.cdt.internal.docker.launcher.ContainerLaunchUtils; import org.eclipse.cdt.internal.docker.launcher.Messages; import org.eclipse.cdt.internal.docker.launcher.PreferenceConstants; import org.eclipse.cdt.managedbuilder.buildproperties.IOptionalBuildProperties; @@ -158,23 +174,16 @@ public class ContainerCommandLauncher implements ICommandLauncher, ICBuildComman labels.put("org.eclipse.cdt.project-name", projectName); //$NON-NLS-1$ List additionalDirs = new ArrayList<>(); + List additionalPaths = new ArrayList<>(); - // - IPath projectLocation = fProject.getLocation(); - String projectPath = projectLocation.toPortableString(); - if (projectLocation.getDevice() != null) { - projectPath = "/" + projectPath.replace(':', '/'); //$NON-NLS-1$ - } - additionalDirs.add(projectPath); + additionalPaths.add(fProject.getLocation()); ArrayList commandSegments = new ArrayList<>(); List cmdList = new ArrayList<>(); - String commandString = commandPath.toPortableString(); - if (commandPath.getDevice() != null) { - commandString = "/" + commandString.replace(':', '/'); //$NON-NLS-1$ - } + String commandString = ContainerLaunchUtils.toDockerPath(commandPath); + cmdList.add(commandString); commandSegments.add(commandString); for (String arg : args) { @@ -189,12 +198,11 @@ public class ContainerCommandLauncher implements ICommandLauncher, ICBuildComman // and modify the argument to be unix-style if (f.isFile() || f.isDirectory()) { f = f.getParentFile(); - modifiedArg = "/" //$NON-NLS-1$ - + p.toPortableString().replace(':', '/'); + modifiedArg = ContainerLaunchUtils.toDockerPath(p); p = p.removeLastSegments(1); } if (f != null && f.exists()) { - additionalDirs.add("/" + p.toPortableString().replace(':', '/')); //$NON-NLS-1$ + additionalPaths.add(p); realArg = modifiedArg; } } @@ -206,9 +214,10 @@ public class ContainerCommandLauncher implements ICommandLauncher, ICBuildComman File f = p.toFile(); if (f.isFile()) { f = f.getParentFile(); + p.removeLastSegments(1); } if (f != null && f.exists()) { - additionalDirs.add(f.getAbsolutePath()); + additionalPaths.add(p); } } } @@ -220,19 +229,15 @@ public class ContainerCommandLauncher implements ICommandLauncher, ICBuildComman IProject[] referencedProjects = fProject.getReferencedProjects(); for (IProject referencedProject : referencedProjects) { - String referencedProjectPath = referencedProject.getLocation().toPortableString(); - if (referencedProject.getLocation().getDevice() != null) { - referencedProjectPath = "/" //$NON-NLS-1$ - + referencedProjectPath.replace(':', '/'); - } - additionalDirs.add(referencedProjectPath); + IPath referencedProjectPath = referencedProject.getLocation(); + additionalPaths.add(referencedProjectPath); } - String workingDir = workingDirectory.makeAbsolute().toPortableString(); + String workingDir; if (workingDirectory.toPortableString().equals(".")) { //$NON-NLS-1$ workingDir = "/tmp"; //$NON-NLS-1$ - } else if (workingDirectory.getDevice() != null) { - workingDir = "/" + workingDir.replace(':', '/'); //$NON-NLS-1$ + } else { + workingDir = ContainerLaunchUtils.toDockerPath(workingDirectory.makeAbsolute()); } parseEnvironment(env); Map origEnv = null; @@ -283,6 +288,9 @@ public class ContainerCommandLauncher implements ICommandLauncher, ICBuildComman } setImageName(imageName); + additionalDirs.addAll( + additionalPaths.stream().map(p -> ContainerLaunchUtils.toDockerVolume(p)).collect(Collectors.toList())); + fProcess = launcher.runCommand(connectionName, imageName, fProject, this, cmdList, workingDir, additionalDirs, origEnv, fEnvironment, supportStdin, privilegedMode, labels, keepContainer); 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 13ce4b4bb4a..2f2a064f923 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Red Hat Inc. and others. + * Copyright (c) 2017, 2022 Red Hat Inc. and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -10,16 +10,14 @@ * * Contributors: * Red Hat Inc. - initial API and implementation + * Mathema - Refactor *******************************************************************************/ package org.eclipse.cdt.docker.launcher; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import org.eclipse.cdt.core.ICommandLauncher; import org.eclipse.cdt.core.ICommandLauncherFactory; @@ -50,15 +48,121 @@ import org.eclipse.linuxtools.docker.ui.launch.ContainerLauncher; @SuppressWarnings("restriction") public class ContainerCommandLauncherFactory implements ICommandLauncherFactory, ICommandLauncherFactory2 { - private IProject project; + private IProject m_project; + + /** + * Helper-Struct + */ + private class ImageConnection { + final String connectionName; + final String imageName; + + public ImageConnection(String connectionName, String imageName) { + this.connectionName = connectionName; + this.imageName = imageName; + } + + } + + /** + * Filter out paths that should not be copied from the container + * @param dirs A List of paths that should be filtered + * @return The filtered list + */ + private List filterOutLocalPaths(List dirs) { + String prj = m_project.getLocation().toString(); + return dirs.stream().filter(x -> !(x.startsWith(prj) || x.startsWith("/${ProjName}")) //$NON-NLS-1$ + ).collect(Collectors.toList()); + + } + + /** + * Transform a string into something that can be used as path name + * @param name The name that should be used as part of a path + * @return A string that should be usable as path name + */ + private String normalizeToPathName(String name) { + String cleanName = name.replace("unix:///", "unix_"); //$NON-NLS-1$ //$NON-NLS-2$ + cleanName = cleanName.replace("tcp://", "tcp_"); //$NON-NLS-1$ //$NON-NLS-2$ + cleanName = cleanName.replaceAll("[:/.]", "_"); //$NON-NLS-1$ //$NON-NLS-2$# + assert Path.ROOT.isValidSegment(cleanName) : "Invalid Path - please file a bug"; //$NON-NLS-1$ + return cleanName; + } + + /** + * Convert the ImageConnection to the local path where the data is mirrored to + * @param imgCon The connection + * @return A host path + */ + private IPath getHostMirrorPath(ImageConnection imgCon) { + IPath pluginPath = Platform.getStateLocation(Platform.getBundle(DockerLaunchUIPlugin.PLUGIN_ID)) + .append("HEADERS"); //$NON-NLS-1$ + pluginPath = pluginPath.append(normalizeToPathName(imgCon.connectionName)); + pluginPath = pluginPath.append(normalizeToPathName(imgCon.imageName)); + return pluginPath; + } + + /** + * Mirror a list of paths from the imgCon to the host + * @param imgCon The image and connection to copy from + * @param paths The paths to copy + * @return Whether the operation was successful + */ + private boolean getPaths(ImageConnection imgCon, List paths) { + IPath targetPath = getHostMirrorPath(imgCon); + + ContainerLauncher launcher = new ContainerLauncher(); + int rv = launcher.fetchContainerDirs(imgCon.connectionName, imgCon.imageName, paths, null, targetPath); + return (rv == 0); + + } + + /** + * Get the Image and Connection from the current project configuration + * @return An ImageConnection or null if connection and image are configured + */ + private ImageConnection getImgCnn() { + ICConfigurationDescription cfgd = CoreModel.getDefault().getProjectDescription(m_project) + .getActiveConfiguration(); + IConfiguration cfg = ManagedBuildManager.getConfigurationForDescription(cfgd); + IOptionalBuildProperties props = cfg.getOptionalBuildProperties(); + if (props == null) { + return null; + } + + String enablementProperty = props.getProperty(ContainerCommandLauncher.CONTAINER_BUILD_ENABLED); + if (enablementProperty == null) { + return null; + } + + if (!Boolean.parseBoolean(enablementProperty)) { + return null; + } + + String connectionName = props.getProperty(ContainerCommandLauncher.CONNECTION_ID); + String imageName = props.getProperty(ContainerCommandLauncher.IMAGE_ID); + if (connectionName == null || connectionName.isEmpty() || imageName == null || imageName.isEmpty()) { + DockerLaunchUIPlugin.logErrorMessage(Messages.ContainerCommandLauncher_invalid_values); + return null; + } + + return new ImageConnection(connectionName, imageName); + + } @Override public ICommandLauncher getCommandLauncher(IProject project) { - this.project = project; + m_project = project; // check if container build enablement has been checked ICConfigurationDescription cfgd = CoreModel.getDefault().getProjectDescription(project, false) .getActiveConfiguration(); + return getCommandLauncher(cfgd); + } + + @Override + public ICommandLauncher getCommandLauncher(ICConfigurationDescription cfgd) { + // check if container build enablement has been checked IConfiguration cfg = null; try { @@ -79,31 +183,8 @@ public class ContainerCommandLauncherFactory implements ICommandLauncherFactory, if (cfg == null) { return null; } - IOptionalBuildProperties props = cfg.getOptionalBuildProperties(); - if (props != null) { - String enablementProperty = props.getProperty(ContainerCommandLauncher.CONTAINER_BUILD_ENABLED); - if (enablementProperty != null) { - boolean enableContainer = Boolean.parseBoolean(enablementProperty); - // enablement has occurred, we can return a - // ContainerCommandLauncher - if (enableContainer) { - return new ContainerCommandLauncher(); - } - } - } - return null; - } - - @Override - public ICommandLauncher getCommandLauncher(ICConfigurationDescription cfgd) { - // check if container build enablement has been checked - IConfiguration cfg = ManagedBuildManager.getConfigurationForDescription(cfgd); - // TODO: figure out why this occurs - if (cfg == null) { - return null; - } - this.project = (IProject) cfg.getManagedProject().getOwner(); + m_project = (IProject) cfg.getManagedProject().getOwner(); IOptionalBuildProperties props = cfg.getOptionalBuildProperties(); if (props != null) { String enablementProperty = props.getProperty(ContainerCommandLauncher.CONTAINER_BUILD_ENABLED); @@ -122,7 +203,7 @@ public class ContainerCommandLauncherFactory implements ICommandLauncherFactory, @Override public ICommandLauncher getCommandLauncher(ICBuildConfiguration cfgd) { try { - this.project = cfgd.getBuildConfiguration().getProject(); + m_project = cfgd.getBuildConfiguration().getProject(); } catch (CoreException e1) { return null; } @@ -143,97 +224,32 @@ public class ContainerCommandLauncherFactory implements ICommandLauncherFactory, @Override public void registerLanguageSettingEntries(IProject project, List langEntries) { - @SuppressWarnings("unchecked") - List entries = (List) langEntries; if (langEntries == null) { // langEntries can be null when the last item is removed from a list, // see org.eclipse.cdt.internal.ui.language.settings.providers.LanguageSettingsEntriesTab.saveEntries(ILanguageSettingsProvider, List) // for an example that passes null to mean "use parent entries instead". return; } - ICConfigurationDescription cfgd = CoreModel.getDefault().getProjectDescription(project) - .getActiveConfiguration(); - IConfiguration cfg = ManagedBuildManager.getConfigurationForDescription(cfgd); - IOptionalBuildProperties props = cfg.getOptionalBuildProperties(); - if (props != null) { - String enablementProperty = props.getProperty(ContainerCommandLauncher.CONTAINER_BUILD_ENABLED); - if (enablementProperty != null) { - boolean enableContainer = Boolean.parseBoolean(enablementProperty); - if (enableContainer) { - String connectionName = props.getProperty(ContainerCommandLauncher.CONNECTION_ID); - String imageName = props.getProperty(ContainerCommandLauncher.IMAGE_ID); - if (connectionName == null || connectionName.isEmpty() || imageName == null - || imageName.isEmpty()) { - DockerLaunchUIPlugin.logErrorMessage(Messages.ContainerCommandLauncher_invalid_values); - return; - } - ContainerLauncher launcher = new ContainerLauncher(); - List paths = new ArrayList<>(); - for (ICLanguageSettingEntry entry : entries) { - if (entry instanceof ICIncludePathEntry) { - paths.add(entry.getValue()); - } else if (entry instanceof ICIncludeFileEntry) { - paths.add(new org.eclipse.core.runtime.Path(entry.getValue()).removeLastSegments(1) - .toString()); - } - } - if (paths.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; - } - 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; - } - } catch (IOException e) { - DockerLaunchUIPlugin.log(e); - return; - } - IPath hostDir = pluginPath; - List excludeList = new ArrayList<>(); - excludeList.add(project.getLocation().toString()); - @SuppressWarnings("unused") - int status = launcher.fetchContainerDirs(connectionName, imageName, paths, excludeList, - hostDir); - } - } + + @SuppressWarnings("unchecked") + List entries = (List) langEntries; + + List paths = new ArrayList<>(); + for (ICLanguageSettingEntry entry : entries) { + if (entry instanceof ICIncludePathEntry) { + paths.add(entry.getValue()); + } else if (entry instanceof ICIncludeFileEntry) { + paths.add(new org.eclipse.core.runtime.Path(entry.getValue()).removeLastSegments(1).toString()); } } + paths = filterOutLocalPaths(paths); + if (paths.size() == 0) { + return; + } + ImageConnection imgCnn = getImgCnn(); + getPaths(imgCnn, paths); + } /** @@ -242,109 +258,72 @@ public class ContainerCommandLauncherFactory implements ICommandLauncherFactory, @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; - } - if (includePaths.size() > 0) { - ContainerLauncher launcher = new ContainerLauncher(); - // 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; - // exclude project directories from any copying operation - List excludeList = new ArrayList<>(); - excludeList.add(project.getLocation().toString()); - int status = launcher.fetchContainerDirsSync(connectionName, imageName, includePaths, excludeList, - hostDir); - if (status == 0) { - Set copiedVolumes = launcher.getCopiedVolumes(connectionName, imageName); - List newEntries = new ArrayList<>(); + if (toolchain == null) { + return includePaths; + } - 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; - } + if (!ContainerTargetTypeProvider.CONTAINER_LINUX.equals(toolchain.getProperty(IToolChain.ATTR_OS))) { + DockerLaunchUIPlugin.logErrorMessage(Messages.ContainerCommandLauncher_invalid_container_type); + return includePaths; + } + 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; + } + + ImageConnection imgCnn = new ImageConnection(connectionName, imageName); + + if (includePaths.isEmpty()) { + // Bug 536884 - if no include entries, check if the copied + // header files have been erased by the end-user in which + // case mark that scanner info needs refreshing (only way + // the headers will be recopied) + // TODO: fix this in a minor release to be an additional method + // that can be registered by the removal of the header files + IPath pluginPath = getHostMirrorPath(imgCnn); + toolchain.setProperty("cdt.needScannerRefresh", //$NON-NLS-1$ + pluginPath.toFile().exists() ? "false" : "true"); //$NON-NLS-1$ //$NON-NLS-2$ + return includePaths; + } + + List fetchPaths = filterOutLocalPaths(includePaths); + if (fetchPaths.size() == 0) { + return includePaths; + } + + if (!getPaths(imgCnn, includePaths)) { + // There should be sufficient log messages by the root cause + return includePaths; + } + + // Do the actual work + + IPath tpath = getHostMirrorPath(imgCnn); + Set copiedVolumes = ContainerLauncher.getCopiedVolumes(tpath); + List newEntries = new ArrayList<>(); + + for (String path : includePaths) { + if (copiedVolumes.contains(new Path(path))) { + IPath newPath = tpath.append(path); + String newEntry = newPath.toOSString(); + newEntries.add(newEntry); } else { - // Bug 536884 - if no include entries, check if the copied - // header files have been erased by the end-user in which - // case mark that scanner info needs refreshing (only way - // the headers will be recopied) - // TODO: fix this in a minor release to be an additional method - // that can be registered by the removal of the header files - IPath pluginPath = Platform.getStateLocation(Platform.getBundle(DockerLaunchUIPlugin.PLUGIN_ID)) - .append("HEADERS").append(getCleanName(connectionName)) //$NON-NLS-1$ - .append(getCleanName(imageName)); - toolchain.setProperty("cdt.needScannerRefresh", //$NON-NLS-1$ - pluginPath.toFile().exists() ? "false" : "true"); //$NON-NLS-1$ //$NON-NLS-2$ + newEntries.add(path); } } - return includePaths; + return newEntries; + } @Override @@ -353,64 +332,56 @@ public class ContainerCommandLauncherFactory implements ICommandLauncherFactory, if (entries == null) { return null; } + ICConfigurationDescription cfgd = CoreModel.getDefault().getProjectDescription(project) .getActiveConfiguration(); IConfiguration cfg = ManagedBuildManager.getConfigurationForDescription(cfgd); IOptionalBuildProperties props = cfg.getOptionalBuildProperties(); - if (props != null) { - String enablementProperty = props.getProperty(ContainerCommandLauncher.CONTAINER_BUILD_ENABLED); - if (enablementProperty != null) { - boolean enableContainer = Boolean.parseBoolean(enablementProperty); - if (enableContainer) { - String connectionName = props.getProperty(ContainerCommandLauncher.CONNECTION_ID); - String imageName = props.getProperty(ContainerCommandLauncher.IMAGE_ID); - if (connectionName == null || connectionName.isEmpty() || imageName == null - || imageName.isEmpty()) { - DockerLaunchUIPlugin.logErrorMessage(Messages.ContainerCommandLauncher_invalid_values); - return entries; - } - ContainerLauncher launcher = new ContainerLauncher(); - Set copiedVolumes = launcher.getCopiedVolumes(connectionName, imageName); - List newEntries = new ArrayList<>(); - IPath pluginPath = Platform.getStateLocation(Platform.getBundle(DockerLaunchUIPlugin.PLUGIN_ID)); - IPath hostDir = pluginPath.append("HEADERS") //$NON-NLS-1$ - .append(getCleanName(connectionName)).append(getCleanName(imageName)); + if (props == null) + return entries; - for (ICLanguageSettingEntry entry : entries) { - if (entry instanceof ICIncludePathEntry) { - if (copiedVolumes.contains(((ICIncludePathEntry) entry).getName().toString())) { - // //$NON-NLS-2$ - IPath newPath = hostDir.append(entry.getName()); - CIncludePathEntry newEntry = new CIncludePathEntry(newPath.toString(), - entry.getFlags()); - newEntries.add(newEntry); - continue; - } - } - if (entry instanceof ICIncludeFileEntry) { - IPath p = new Path(((ICIncludeFileEntry) entry).getName()); - if (copiedVolumes.contains(p.removeLastSegments(1).toString())) { - IPath newPath = hostDir.append(entry.getName()); - CIncludeFileEntry newEntry = new CIncludeFileEntry(newPath.toString(), - entry.getFlags()); - newEntries.add(newEntry); - continue; - } - } - newEntries.add(entry); - } - return newEntries; + String enablementProperty = props.getProperty(ContainerCommandLauncher.CONTAINER_BUILD_ENABLED); + if (enablementProperty == null) + return entries; + + boolean enableContainer = Boolean.parseBoolean(enablementProperty); + if (!enableContainer) + return entries; + + String connectionName = props.getProperty(ContainerCommandLauncher.CONNECTION_ID); + String imageName = props.getProperty(ContainerCommandLauncher.IMAGE_ID); + if (connectionName == null || connectionName.isEmpty() || imageName == null || imageName.isEmpty()) { + DockerLaunchUIPlugin.logErrorMessage(Messages.ContainerCommandLauncher_invalid_values); + return entries; + } + + IPath tpath = getHostMirrorPath(new ImageConnection(connectionName, imageName)); + Set copiedVolumes = ContainerLauncher.getCopiedVolumes(tpath); + List newEntries = new ArrayList<>(); + + for (ICLanguageSettingEntry entry : entries) { + if (entry instanceof ICIncludePathEntry) { + Path tp = new Path(((ICIncludePathEntry) entry).getName().toString()); + if (copiedVolumes.stream().anyMatch(p -> p.isPrefixOf(tp))) { + IPath newPath = tpath.append(entry.getName()); + CIncludePathEntry newEntry = new CIncludePathEntry(newPath.toString(), entry.getFlags()); + newEntries.add(newEntry); + continue; } } + if (entry instanceof ICIncludeFileEntry) { + IPath tp = new Path(((ICIncludeFileEntry) entry).getName()).removeLastSegments(1); + if (copiedVolumes.stream().anyMatch(p -> p.isPrefixOf(tp))) { + IPath newPath = tpath.append(entry.getName()); + CIncludeFileEntry newEntry = new CIncludeFileEntry(newPath.toString(), entry.getFlags()); + newEntries.add(newEntry); + continue; + } + } + newEntries.add(entry); } - return entries; - } - - private String getCleanName(String name) { - String cleanName = name.replace("unix:///", "unix_"); //$NON-NLS-1$ //$NON-NLS-2$ - cleanName = cleanName.replace("tcp://", "tcp_"); //$NON-NLS-1$ //$NON-NLS-2$ - return cleanName.replaceAll("[:/.]", "_"); //$NON-NLS-1$ //$NON-NLS-2$ + return newEntries; } } 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 ae370e8f98d..15ba069db6e 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015, 2020 Red Hat and others. + * Copyright (c) 2015, 2022 Red Hat and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -160,13 +160,8 @@ public class ContainerLaunchConfigurationDelegate extends GdbLaunchDelegate { String projectName = configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, ""); //$NON-NLS-1$ labels.put("org.eclipse.cdt.project-name", projectName); //$NON-NLS-1$ if (mode.equals(ILaunchManager.RUN_MODE)) { - String commandDir = commandPath.removeLastSegments(1).toPortableString(); - String commandString = commandPath.toPortableString(); - - if (commandPath.getDevice() != null) { - commandDir = "/" + commandDir.replace(':', '/'); //$NON-NLS-1$ - commandString = "/" + commandString.replace(':', '/'); //$NON-NLS-1$ - } + String commandDir = ContainerLaunchUtils.toDockerPath(commandPath.removeLastSegments(1)); + String commandString = ContainerLaunchUtils.toDockerPath(commandPath); StringBuilder b = new StringBuilder(); b.append(commandString); @@ -191,8 +186,7 @@ public class ContainerLaunchConfigurationDelegate extends GdbLaunchDelegate { if (workingDir != null) { IPath workingPath = new Path(workingDir); if (workingPath.getDevice() != null) { - workingDir = "/" + workingPath.toPortableString() //$NON-NLS-1$ - .replace(':', '/'); + workingDir = ContainerLaunchUtils.toDockerPath(workingPath); } } Map envMap = configuration.getAttribute(ILaunchManager.ATTR_ENVIRONMENT_VARIABLES, @@ -208,10 +202,8 @@ public class ContainerLaunchConfigurationDelegate extends GdbLaunchDelegate { List dirs = new ArrayList<>(); for (String additionalDir : additionalDirs) { IPath path = new Path(additionalDir); - String dir = path.toPortableString(); - if (path.getDevice() != null) { - dir = "/" + dir.replace(':', '/'); //$NON-NLS-1$ - } + String dir = ContainerLaunchUtils.toDockerPath(path); + dirs.add(dir); } additionalDirs = dirs; @@ -298,13 +290,8 @@ public class ContainerLaunchConfigurationDelegate extends GdbLaunchDelegate { String gdbserverCommand = configuration.getAttribute(ILaunchConstants.ATTR_GDBSERVER_COMMAND, ILaunchConstants.ATTR_GDBSERVER_COMMAND_DEFAULT); - String commandString = commandPath.toPortableString(); - String commandDir = commandPath.removeLastSegments(1).toPortableString(); - - if (commandPath.getDevice() != null) { - commandDir = "/" + commandDir.replace(':', '/'); //$NON-NLS-1$ - commandString = "/" + commandString.replace(':', '/'); //$NON-NLS-1$ - } + String commandString = ContainerLaunchUtils.toDockerPath(commandPath); + String commandDir = ContainerLaunchUtils.toDockerPath(commandPath.removeLastSegments(1)); String commandArguments = ":" + gdbserverPortNumber + " " //$NON-NLS-1$ //$NON-NLS-2$ + spaceEscapify(commandString); @@ -331,8 +318,7 @@ public class ContainerLaunchConfigurationDelegate extends GdbLaunchDelegate { if (workingDir != null) { IPath workingPath = new Path(workingDir); if (workingPath.getDevice() != null) { - workingDir = "/" + workingPath.toPortableString() //$NON-NLS-1$ - .replace(':', '/'); + workingDir = ContainerLaunchUtils.toDockerPath(workingPath); } } @@ -349,10 +335,7 @@ public class ContainerLaunchConfigurationDelegate extends GdbLaunchDelegate { List dirs = new ArrayList<>(); for (String additionalDir : additionalDirs) { IPath path = new Path(additionalDir); - String dir = path.toPortableString(); - if (path.getDevice() != null) { - dir = "/" + dir.replace(':', '/'); //$NON-NLS-1$ - } + String dir = ContainerLaunchUtils.toDockerPath(path); dirs.add(dir); } additionalDirs = dirs; diff --git a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ContainerLaunchUtils.java b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ContainerLaunchUtils.java new file mode 100644 index 00000000000..ff55ba042b9 --- /dev/null +++ b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ContainerLaunchUtils.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2022 Red Hat Inc. and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.docker.launcher; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Platform; + +public class ContainerLaunchUtils { + + /** + * Maps the local path, to a path that is used within a docker container. + * @param path The host path + * @return the path within the docker container + * @see toDockerPath(String) + */ + public static final String toDockerPath(IPath path) { + String pathstring = path.toPortableString(); + if (path.getDevice() != null) { + if (pathstring.charAt(0) != '/') { + pathstring = '/' + pathstring; + } + } + return ContainerLaunchUtils.toDockerPath(pathstring); + + } + + /** + * Maps the local path, to a path that is used within a docker container. + * C: is mapped to /c, etc. + * //$WSL// is a bit more tricky. For now it will be mapped to /WSL// + * @param path The host path + * @return the path within the docker container + */ + public static final String toDockerPath(String path) { + if (Platform.getOS().equals(Platform.OS_WIN32)) { + path = path.replace(':', '/'); + //Fix WSL which starts with //$WSL - TODO: Make more robust + path = path.replace("//WSL$/", "/WSL/"); //$NON-NLS-1$ //$NON-NLS-2$ + } + //Ensure the path is global. + + return path; + } + + /** + * Convert a Path to a string that can be passed as docker volume to be mapped into the Docker container + * toDockerPath() is used to get the path within the Docker container. + * @param path The path on the hose + * @return The string to be passed to the docker daemon + */ + public static final String toDockerVolume(IPath path) { + IPath p = path.makeAbsolute(); + String rv = toDockerPath(p); + rv += ":HOST_FILE_SYSTEM:"; //$NON-NLS-1$ + rv += p.toOSString(); + rv += ":false:true"; //$NON-NLS-1$ RO=false, selected = true + return rv; + } + +} 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 571a6930972..ebe386b5df4 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2020 Red Hat, Inc. + * Copyright (c) 2012, 2022 Red Hat, Inc. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -32,12 +32,12 @@ public class Messages extends NLS { public static String LaunchShortcut_Launcher; public static String Default_Image; public static String Keep_Container_After_Launch; + public static String ContainerTab_Name; public static String ContainerTab_Group_Name; public static String ContainerTab_Option_Group_Name; public static String ContainerTab_Ports_Group_Name; public static String ContainerTab_Specify_Ports_Label; - public static String ContainerTab_Add_Button; public static String ContainerTab_Edit_Button; public static String ContainerTab_New_Button; @@ -123,6 +123,7 @@ public class Messages extends NLS { public static String ContainerTarget_name; public static String ContainerCommandLauncher_invalid_values; + public static String ContainerCommandLauncher_invalid_container_type; 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 dfd2c3dff1a..c2542845474 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 @@ -1,5 +1,5 @@ #******************************************************************************* -# Copyright (c) 2015, 2020 Red Hat. +# Copyright (c) 2015, 2022 Red Hat. # # This program and the accompanying materials # are made available under the terms of the Eclipse Public License 2.0 @@ -77,6 +77,7 @@ HeaderPreferencePage_Confirm_Removal_Msg=Confirm removal of specified cached hea ContainerCommandLauncher_image_msg=[Running in image <{0}>] ContainerCommandLauncher_invalid_values=Invalid values for Connection and/or Image name +ContainerCommandLauncher_invalid_container_type=Toolchain is not a Linux Container toolchain CommandLauncher_CommandCancelled=Command cancelled