diff --git a/build/org.eclipse.cdt.autotools.core/src/org/eclipse/cdt/internal/autotools/core/AutotoolsNewMakeGenerator.java b/build/org.eclipse.cdt.autotools.core/src/org/eclipse/cdt/internal/autotools/core/AutotoolsNewMakeGenerator.java index 813fd3b4b50..2833538ef0f 100644 --- a/build/org.eclipse.cdt.autotools.core/src/org/eclipse/cdt/internal/autotools/core/AutotoolsNewMakeGenerator.java +++ b/build/org.eclipse.cdt.autotools.core/src/org/eclipse/cdt/internal/autotools/core/AutotoolsNewMakeGenerator.java @@ -893,7 +893,7 @@ public class AutotoolsNewMakeGenerator extends MarkerGenerator { consoleOutStream.flush(); // Get a launcher for the config command - RemoteCommandLauncher launcher = new RemoteCommandLauncher(); + ICommandLauncher launcher = new RemoteCommandLauncher(); launcher.setProject(project); // Set the environment IEnvironmentVariable variables[] = @@ -1207,7 +1207,7 @@ public class AutotoolsNewMakeGenerator extends MarkerGenerator { consoleOutStream.flush(); // Get a launcher for the config command - RemoteCommandLauncher launcher = new RemoteCommandLauncher(); + ICommandLauncher launcher = new RemoteCommandLauncher(); launcher.setProject(project); // Set the environment IEnvironmentVariable variables[] = diff --git a/build/org.eclipse.cdt.autotools.tests/src/org/eclipse/cdt/autotools/tests/ProjectTools.java b/build/org.eclipse.cdt.autotools.tests/src/org/eclipse/cdt/autotools/tests/ProjectTools.java index ad5aad0d3bd..e2df9dc56b8 100644 --- a/build/org.eclipse.cdt.autotools.tests/src/org/eclipse/cdt/autotools/tests/ProjectTools.java +++ b/build/org.eclipse.cdt.autotools.tests/src/org/eclipse/cdt/autotools/tests/ProjectTools.java @@ -18,6 +18,8 @@ import java.util.zip.ZipFile; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.CommandLauncher; +import org.eclipse.cdt.core.CommandLauncherFactoryManager; +import org.eclipse.cdt.core.ICommandLauncher; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.internal.autotools.core.configure.AutotoolsConfigurationManager; import org.eclipse.cdt.internal.autotools.core.configure.IAConfiguration; @@ -129,7 +131,8 @@ public class ProjectTools { */ public static boolean markExecutable(IProject project, String filePath) { // Get a launcher for the config command - CommandLauncher launcher = new CommandLauncher(); + ICommandLauncher launcher = CommandLauncherFactoryManager.getInstance().getCommandLauncher(); + launcher.setProject(project); OutputStream stdout = new ByteArrayOutputStream(); OutputStream stderr = new ByteArrayOutputStream(); diff --git a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/MakeBuilder.java b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/MakeBuilder.java index 4d9b9ad51c1..cffa0635fe5 100644 --- a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/MakeBuilder.java +++ b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/MakeBuilder.java @@ -23,7 +23,7 @@ import java.util.List; import java.util.Map; import org.eclipse.cdt.core.CCorePlugin; -import org.eclipse.cdt.core.CommandLauncher; +import org.eclipse.cdt.core.CommandLauncherFactoryManager; import org.eclipse.cdt.core.ErrorParserManager; import org.eclipse.cdt.core.ICommandLauncher; import org.eclipse.cdt.core.IConsoleParser; @@ -180,7 +180,7 @@ public class MakeBuilder extends ACBuilder { console.start(project); // Prepare launch parameters for BuildRunnerHelper - ICommandLauncher launcher = new CommandLauncher(); + ICommandLauncher launcher = CommandLauncherFactoryManager.getInstance().getCommandLauncher(); String[] targets = getTargets(kind, info); if (targets.length != 0 && targets[targets.length - 1].equals(info.getCleanBuildTarget())) diff --git a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/scannerconfig2/DefaultRunSIProvider.java b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/scannerconfig2/DefaultRunSIProvider.java index cd8b03563be..787d23f48ed 100644 --- a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/scannerconfig2/DefaultRunSIProvider.java +++ b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/scannerconfig2/DefaultRunSIProvider.java @@ -19,7 +19,7 @@ import java.util.List; import java.util.Properties; import org.eclipse.cdt.core.CCorePlugin; -import org.eclipse.cdt.core.CommandLauncher; +import org.eclipse.cdt.core.CommandLauncherFactoryManager; import org.eclipse.cdt.core.ErrorParserManager; import org.eclipse.cdt.core.ICommandLauncher; import org.eclipse.cdt.core.IConsoleParser; @@ -120,7 +120,7 @@ public class DefaultRunSIProvider implements IExternalScannerInfoProvider { } console.start(project); - ICommandLauncher launcher = new CommandLauncher(); + ICommandLauncher launcher = CommandLauncherFactoryManager.getInstance().getCommandLauncher(); launcher.setProject(project); IPath program = getCommandToLaunch(); diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/buildproperties/IOptionalBuildProperties.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/buildproperties/IOptionalBuildProperties.java new file mode 100644 index 00000000000..23043aed061 --- /dev/null +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/buildproperties/IOptionalBuildProperties.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2017 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 API and implementation + *******************************************************************************/ +package org.eclipse.cdt.managedbuilder.buildproperties; + +/** + * @noextend This class is not intended to be subclassed by clients. + * @noimplement This interface is not intended to be implemented by clients. + * @since 8.5 + */ +public interface IOptionalBuildProperties extends Cloneable { + String[] getProperties(); + + String getProperty(String id); + + void setProperty(String propertyId, String propertyValue); + + void removeProperty(String id); + + void clear(); + + Object clone(); +} \ No newline at end of file diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IBuildObjectPropertiesContainer.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IBuildObjectPropertiesContainer.java index 3bc55876f69..a3704a24f05 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IBuildObjectPropertiesContainer.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IBuildObjectPropertiesContainer.java @@ -10,7 +10,6 @@ *******************************************************************************/ package org.eclipse.cdt.managedbuilder.core; - /** * @noextend This class is not intended to be subclassed by clients. * @noimplement This interface is not intended to be implemented by clients. diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IConfiguration.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IConfiguration.java index f04149faefa..81d1f28bbb1 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IConfiguration.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IConfiguration.java @@ -36,7 +36,7 @@ import org.eclipse.core.runtime.IPath; * @noextend This class is not intended to be subclassed by clients. * @noimplement This interface is not intended to be implemented by clients. */ -public interface IConfiguration extends IBuildObject, IBuildObjectPropertiesContainer { +public interface IConfiguration extends IBuildObject, IBuildObjectPropertiesContainer, IOptionalBuildObjectPropertiesContainer { public static final String ARTIFACT_NAME = "artifactName"; //$NON-NLS-1$ public static final String CLEAN_COMMAND = "cleanCommand"; //$NON-NLS-1$ public static final String PREBUILD_STEP = "prebuildStep"; //$NON-NLS-1$ @@ -54,6 +54,10 @@ public interface IConfiguration extends IBuildObject, IBuildObjectPropertiesCont public static final String DESCRIPTION = "description"; //$NON-NLS-1$ public static final String BUILD_PROPERTIES = "buildProperties"; //$NON-NLS-1$ + /** + * @since 8.5 + */ + public static final String OPTIONAL_BUILD_PROPERTIES = "optionalBuildProperties"; //$NON-NLS-1$ public static final String BUILD_ARTEFACT_TYPE = "buildArtefactType"; //$NON-NLS-1$ public static final String IS_SYSTEM = "isSystem"; //$NON-NLS-1$ diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IManagedProject.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IManagedProject.java index e0d527e9392..8e5a0d7857f 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IManagedProject.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IManagedProject.java @@ -38,10 +38,14 @@ import org.eclipse.core.resources.IResource; * @noextend This class is not intended to be subclassed by clients. * @noimplement This interface is not intended to be implemented by clients. */ -public interface IManagedProject extends IBuildObject, IBuildObjectPropertiesContainer { +public interface IManagedProject extends IBuildObject, IBuildObjectPropertiesContainer, IOptionalBuildObjectPropertiesContainer { public static final String MANAGED_PROJECT_ELEMENT_NAME = "project"; //$NON-NLS-1$ public static final String PROJECTTYPE = "projectType"; //$NON-NLS-1$ public static final String BUILD_PROPERTIES = "buildProperties"; //$NON-NLS-1$ + /** + * @since 8.5 + */ + public static final String OPTIONAL_BUILD_PROPERTIES = "optionalBuildProperties"; //$NON-NLS-1$ public static final String BUILD_ARTEFACT_TYPE = "buildArtefactType"; //$NON-NLS-1$ diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IOptionalBuildObjectPropertiesContainer.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IOptionalBuildObjectPropertiesContainer.java new file mode 100644 index 00000000000..68cfa186bcb --- /dev/null +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IOptionalBuildObjectPropertiesContainer.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2017 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 API and implementation + *******************************************************************************/ +package org.eclipse.cdt.managedbuilder.core; + +import org.eclipse.cdt.managedbuilder.buildproperties.IOptionalBuildProperties; + +/** + * @since 8.5 + */ +public interface IOptionalBuildObjectPropertiesContainer { + IOptionalBuildProperties getOptionalBuildProperties(); + +} diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IProjectType.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IProjectType.java index 1eea850c358..6d810e7110d 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IProjectType.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IProjectType.java @@ -44,7 +44,7 @@ import org.eclipse.cdt.managedbuilder.macros.IProjectBuildMacroSupplier; * @noextend This class is not intended to be subclassed by clients. * @noimplement This interface is not intended to be implemented by clients. */ -public interface IProjectType extends IBuildObject, IBuildObjectPropertiesContainer { +public interface IProjectType extends IBuildObject, IBuildObjectPropertiesContainer, IOptionalBuildObjectPropertiesContainer { public static final String PROJECTTYPE_ELEMENT_NAME = "projectType"; //$NON-NLS-1$ public static final String SUPERCLASS = "superClass"; //$NON-NLS-1$ public static final String IS_ABSTRACT = "isAbstract"; //$NON-NLS-1$ diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/buildmodel/CommandBuilder.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/buildmodel/CommandBuilder.java index 4fe8091783a..7bcec107c79 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/buildmodel/CommandBuilder.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/buildmodel/CommandBuilder.java @@ -18,7 +18,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import org.eclipse.cdt.core.CommandLauncher; +import org.eclipse.cdt.core.CommandLauncherFactoryManager; import org.eclipse.cdt.core.ICommandLauncher; import org.eclipse.cdt.managedbuilder.buildmodel.IBuildCommand; import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin; @@ -143,7 +143,7 @@ public class CommandBuilder implements IBuildModelBuilder { } protected ICommandLauncher createLauncher() { - return new CommandLauncher(); + return CommandLauncherFactoryManager.getInstance().getCommandLauncher(); } public String getErrMsg() { diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/Builder.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/Builder.java index 2b61d3e6cac..914a6f1e928 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/Builder.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/Builder.java @@ -25,7 +25,7 @@ import java.util.SortedMap; import java.util.StringTokenizer; import org.eclipse.cdt.core.CCorePlugin; -import org.eclipse.cdt.core.CommandLauncher; +import org.eclipse.cdt.core.CommandLauncherFactoryManager; import org.eclipse.cdt.core.ErrorParserManager; import org.eclipse.cdt.core.ICommandLauncher; import org.eclipse.cdt.core.cdtvariables.CdtVariableException; @@ -2858,7 +2858,7 @@ public class Builder extends HoldsOptions implements IBuilder, IMatchKeyProvider return getSuperClass().getCommandLauncher(); else if(fCommandLauncher == null) // catch all for backwards compatibility - fCommandLauncher = new CommandLauncher(); + fCommandLauncher = CommandLauncherFactoryManager.getInstance().getCommandLauncher(); return fCommandLauncher; } diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/Configuration.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/Configuration.java index bba687d8168..ac7b3f22ae8 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/Configuration.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/Configuration.java @@ -45,6 +45,7 @@ import org.eclipse.cdt.internal.core.SafeStringInterner; import org.eclipse.cdt.managedbuilder.buildproperties.IBuildProperty; import org.eclipse.cdt.managedbuilder.buildproperties.IBuildPropertyType; import org.eclipse.cdt.managedbuilder.buildproperties.IBuildPropertyValue; +import org.eclipse.cdt.managedbuilder.buildproperties.IOptionalBuildProperties; import org.eclipse.cdt.managedbuilder.core.BuildException; import org.eclipse.cdt.managedbuilder.core.IBuildObject; import org.eclipse.cdt.managedbuilder.core.IBuildObjectProperties; @@ -114,6 +115,7 @@ public class Configuration extends BuildObject implements IConfiguration, IBuild private String description; private ICSourceEntry[] sourceEntries; private BuildObjectProperties buildProperties; + private OptionalBuildProperties optionalBuildProperties; private boolean isTest; private SupportedProperties supportedProperties; @@ -261,6 +263,10 @@ public class Configuration extends BuildObject implements IConfiguration, IBuild if(props != null) buildProperties = new BuildObjectProperties(props, this, this); + String optionalProps = SafeStringInterner.safeIntern(element.getAttribute(OPTIONAL_BUILD_PROPERTIES)); + if(props != null) + optionalBuildProperties = new OptionalBuildProperties(optionalProps); + String artType = SafeStringInterner.safeIntern(element.getAttribute(BUILD_ARTEFACT_TYPE)); if(artType != null){ if(buildProperties == null) @@ -482,6 +488,9 @@ public class Configuration extends BuildObject implements IConfiguration, IBuild if(baseCfg.buildProperties != null) this.buildProperties = new BuildObjectProperties(baseCfg.buildProperties, this, this); + if (baseCfg.optionalBuildProperties != null) + this.optionalBuildProperties = new OptionalBuildProperties(baseCfg.optionalBuildProperties); + // set managedBuildRevision setManagedBuildRevision(baseCfg.getManagedBuildRevision()); @@ -625,6 +634,10 @@ public class Configuration extends BuildObject implements IConfiguration, IBuild if(cloneConfig.buildProperties != null) { this.buildProperties = new BuildObjectProperties(cloneConfig.buildProperties, this, this); } + + if (cloneConfig.optionalBuildProperties != null) { + this.optionalBuildProperties = new OptionalBuildProperties(cloneConfig.optionalBuildProperties); + } this.description = cloneConfig.getDescription(); @@ -819,6 +832,10 @@ public class Configuration extends BuildObject implements IConfiguration, IBuild if(props != null) buildProperties = new BuildObjectProperties(props, this, this); + String optionalProps = element.getAttribute(OPTIONAL_BUILD_PROPERTIES); + if (optionalProps != null) + optionalBuildProperties = new OptionalBuildProperties(optionalProps); + String artType = SafeStringInterner.safeIntern(element.getAttribute(BUILD_ARTEFACT_TYPE)); if(artType != null){ if(buildProperties == null) @@ -908,6 +925,10 @@ public class Configuration extends BuildObject implements IConfiguration, IBuild } } + if(optionalBuildProperties != null){ + element.setAttribute(OPTIONAL_BUILD_PROPERTIES, optionalBuildProperties.toString()); + } + if (parent != null) element.setAttribute(IConfiguration.PARENT, parent.getId()); @@ -2398,6 +2419,18 @@ public class Configuration extends BuildObject implements IConfiguration, IBuild return buildProperties; } + @Override + public IOptionalBuildProperties getOptionalBuildProperties() { + if (optionalBuildProperties == null){ + OptionalBuildProperties parentProps = findOptionalBuildProperties(); + if(parentProps != null) + optionalBuildProperties = new OptionalBuildProperties(parentProps); + else + optionalBuildProperties = new OptionalBuildProperties(); + } + return optionalBuildProperties; + } + private BuildObjectProperties findBuildProperties(){ if(buildProperties == null){ if(parent != null){ @@ -2407,6 +2440,16 @@ public class Configuration extends BuildObject implements IConfiguration, IBuild } return buildProperties; } + + private OptionalBuildProperties findOptionalBuildProperties(){ + if (optionalBuildProperties == null){ + if (parent != null){ + return ((Configuration)parent).findOptionalBuildProperties(); + } + return null; + } + return optionalBuildProperties; + } public boolean supportsType(IBuildPropertyType type) { return supportsType(type.getId()); diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/ManagedProject.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/ManagedProject.java index 22bbaa7cde2..68d59d2f271 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/ManagedProject.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/ManagedProject.java @@ -24,6 +24,7 @@ import org.eclipse.cdt.core.settings.model.ICStorageElement; import org.eclipse.cdt.internal.core.cdtvariables.StorableCdtVariables; import org.eclipse.cdt.managedbuilder.buildproperties.IBuildPropertyType; import org.eclipse.cdt.managedbuilder.buildproperties.IBuildPropertyValue; +import org.eclipse.cdt.managedbuilder.buildproperties.IOptionalBuildProperties; import org.eclipse.cdt.managedbuilder.core.IBuildObject; import org.eclipse.cdt.managedbuilder.core.IBuildObjectProperties; import org.eclipse.cdt.managedbuilder.core.IBuildPropertiesRestriction; @@ -57,6 +58,7 @@ public class ManagedProject extends BuildObject implements IManagedProject, IBui // private StorableEnvironment userDefinedEnvironment; private BuildObjectProperties buildProperties; + private OptionalBuildProperties optionalBuildProperties; /* * C O N S T R U C T O R S @@ -191,6 +193,10 @@ public class ManagedProject extends BuildObject implements IManagedProject, IBui String props = element.getAttribute(BUILD_PROPERTIES); if(props != null && props.length() != 0) buildProperties = new BuildObjectProperties(props, this, this); + + String optionalProps = element.getAttribute(OPTIONAL_BUILD_PROPERTIES); + if (optionalProps != null && optionalProps.length() != 0) + optionalBuildProperties = new OptionalBuildProperties(optionalProps); String artType = element.getAttribute(BUILD_ARTEFACT_TYPE); if(artType != null){ @@ -576,6 +582,18 @@ public class ManagedProject extends BuildObject implements IManagedProject, IBui return buildProperties; } + @Override + public IOptionalBuildProperties getOptionalBuildProperties() { + if(optionalBuildProperties == null){ + OptionalBuildProperties parentProps = findOptionalBuildProperties(); + if(parentProps != null) + optionalBuildProperties = new OptionalBuildProperties(parentProps); + else + optionalBuildProperties = new OptionalBuildProperties(); + } + return optionalBuildProperties; + } + private BuildObjectProperties findBuildProperties(){ if(buildProperties == null){ if(projectType != null){ @@ -586,6 +604,16 @@ public class ManagedProject extends BuildObject implements IManagedProject, IBui return buildProperties; } + private OptionalBuildProperties findOptionalBuildProperties(){ + if(optionalBuildProperties == null){ + if(projectType != null){ + return ((ProjectType)projectType).findOptionalBuildProperties(); + } + return null; + } + return optionalBuildProperties; + } + @Override public void propertiesChanged() { IConfiguration cfgs[] = getConfigurations(); diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/MultiConfiguration.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/MultiConfiguration.java index f3e9bda6d7f..0a7b5a0e4b6 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/MultiConfiguration.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/MultiConfiguration.java @@ -22,6 +22,7 @@ import org.eclipse.cdt.core.settings.model.extension.CBuildData; import org.eclipse.cdt.core.settings.model.extension.CConfigurationData; import org.eclipse.cdt.managedbuilder.buildproperties.IBuildProperty; import org.eclipse.cdt.managedbuilder.buildproperties.IBuildPropertyValue; +import org.eclipse.cdt.managedbuilder.buildproperties.IOptionalBuildProperties; import org.eclipse.cdt.managedbuilder.core.BuildException; import org.eclipse.cdt.managedbuilder.core.IBuildObjectProperties; import org.eclipse.cdt.managedbuilder.core.IBuilder; @@ -1204,6 +1205,14 @@ public class MultiConfiguration extends MultiItemsHolder implements return curr().getBuildProperties(); } + /* (non-Javadoc) + * @see org.eclipse.cdt.managedbuilder.core.IBuildObjectPropertiesContainer#getOptionalBuildProperties() + */ + @Override + public IOptionalBuildProperties getOptionalBuildProperties() { + return curr().getOptionalBuildProperties(); + } + @Override public boolean getParallelDef() { for (IConfiguration cfg : fCfgs) { diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/OptionalBuildProperties.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/OptionalBuildProperties.java new file mode 100644 index 00000000000..8ec750feba4 --- /dev/null +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/OptionalBuildProperties.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright (c) 2017 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 contribution + *******************************************************************************/ +package org.eclipse.cdt.managedbuilder.internal.core; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.StringTokenizer; + +import org.eclipse.cdt.internal.core.SafeStringInterner; +import org.eclipse.cdt.managedbuilder.buildproperties.IOptionalBuildProperties; + +public class OptionalBuildProperties implements IOptionalBuildProperties { + + public static final String PROPERTY_VALUE_SEPARATOR = "="; //$NON-NLS-1$ + public static final String PROPERTIES_SEPARATOR = ","; //$NON-NLS-1$ + + private Map fProperties = new HashMap<>(); + + public OptionalBuildProperties() { + } + + public OptionalBuildProperties(String properties) { + StringTokenizer t = new StringTokenizer(properties, PROPERTIES_SEPARATOR); + while(t.hasMoreTokens()){ + String property = t.nextToken(); + int index = property.indexOf(PROPERTY_VALUE_SEPARATOR); + String id, value; + if(index != -1){ + id = SafeStringInterner.safeIntern(property.substring(0, index)); + value = SafeStringInterner.safeIntern(property.substring(index + 1)); + } else { + id = SafeStringInterner.safeIntern(property); + value = null; + } + fProperties.put(id, value); + } + } + + public OptionalBuildProperties(OptionalBuildProperties properties) { + fProperties.putAll(properties.fProperties); + } + + @Override + public String getProperty(String id) { + return fProperties.get(id); + } + + @Override + public void setProperty(String id, String value) { + fProperties.put(id, value); + } + + @Override + public String[] getProperties(){ + return fProperties.values().toArray(new String[fProperties.size()]); + } + + @Override + public void removeProperty(String id) { + fProperties.remove(id); + } + + @Override + public String toString(){ + int size = fProperties.size(); + Set> entries = fProperties.entrySet(); + if(size == 0) + return ""; //$NON-NLS-1$ + + StringBuilder buf = new StringBuilder(); + Iterator> iterator = entries.iterator(); + Entry entry = iterator.next(); + buf.append(entry.getKey() + PROPERTY_VALUE_SEPARATOR + entry.getValue()); + + while (iterator.hasNext()) { + buf.append(PROPERTIES_SEPARATOR); + entry = iterator.next(); + buf.append(entry.getKey() + PROPERTY_VALUE_SEPARATOR + entry.getValue()); + } + return buf.toString(); + } + + @Override + public Object clone() { + return new OptionalBuildProperties(this); + } + + @Override + public void clear() { + fProperties.clear(); + } + + +} diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/ProjectType.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/ProjectType.java index 780b7f374e7..c95d833b50d 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/ProjectType.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/ProjectType.java @@ -22,6 +22,7 @@ import org.eclipse.cdt.internal.core.SafeStringInterner; import org.eclipse.cdt.managedbuilder.buildproperties.IBuildProperty; import org.eclipse.cdt.managedbuilder.buildproperties.IBuildPropertyType; import org.eclipse.cdt.managedbuilder.buildproperties.IBuildPropertyValue; +import org.eclipse.cdt.managedbuilder.buildproperties.IOptionalBuildProperties; import org.eclipse.cdt.managedbuilder.core.IBuildObjectProperties; import org.eclipse.cdt.managedbuilder.core.IBuildPropertiesRestriction; import org.eclipse.cdt.managedbuilder.core.IConfiguration; @@ -66,6 +67,7 @@ public class ProjectType extends BuildObject implements IProjectType, IBuildProp private IProjectBuildMacroSupplier buildMacroSupplier = null; BuildObjectProperties buildProperties; + OptionalBuildProperties optionalBuildProperties; // Miscellaneous @@ -707,6 +709,28 @@ public class ProjectType extends BuildObject implements IProjectType, IBuildProp return buildProperties; } + @Override + public IOptionalBuildProperties getOptionalBuildProperties() { + if(optionalBuildProperties == null){ + OptionalBuildProperties parentProps = findOptionalBuildProperties(); + if(parentProps != null) + optionalBuildProperties = new OptionalBuildProperties(parentProps); + else + optionalBuildProperties = new OptionalBuildProperties(); + } + return optionalBuildProperties; + } + + OptionalBuildProperties findOptionalBuildProperties(){ + if(optionalBuildProperties == null){ + if(superClass != null){ + return ((ProjectType)superClass).findOptionalBuildProperties(); + } + return null; + } + return optionalBuildProperties; + } + @Override public void propertiesChanged() { List list = getConfigurationList(); diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/AbstractBuiltinSpecsDetector.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/AbstractBuiltinSpecsDetector.java index 3ed6c149970..b4f98d12a5f 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/AbstractBuiltinSpecsDetector.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/AbstractBuiltinSpecsDetector.java @@ -26,7 +26,7 @@ import java.util.Map.Entry; import java.util.Set; import org.eclipse.cdt.core.CCorePlugin; -import org.eclipse.cdt.core.CommandLauncher; +import org.eclipse.cdt.core.CommandLauncherFactoryManager; import org.eclipse.cdt.core.ErrorParserManager; import org.eclipse.cdt.core.ICommandLauncher; import org.eclipse.cdt.core.IConsoleParser; @@ -656,7 +656,7 @@ public abstract class AbstractBuiltinSpecsDetector extends AbstractLanguageSetti } console.start(currentProject); - ICommandLauncher launcher = new CommandLauncher(); + ICommandLauncher launcher = CommandLauncherFactoryManager.getInstance().getCommandLauncher(); launcher.setProject(currentProject); IPath program = new Path(""); //$NON-NLS-1$ diff --git a/build/org.eclipse.cdt.managedbuilder.ui.tests/src/org/eclipse/cdt/managedbuilder/ui/tests/util/TestConfiguration.java b/build/org.eclipse.cdt.managedbuilder.ui.tests/src/org/eclipse/cdt/managedbuilder/ui/tests/util/TestConfiguration.java index 6bb61e82998..d3c139e359a 100644 --- a/build/org.eclipse.cdt.managedbuilder.ui.tests/src/org/eclipse/cdt/managedbuilder/ui/tests/util/TestConfiguration.java +++ b/build/org.eclipse.cdt.managedbuilder.ui.tests/src/org/eclipse/cdt/managedbuilder/ui/tests/util/TestConfiguration.java @@ -14,6 +14,7 @@ import org.eclipse.cdt.core.settings.model.ICSourceEntry; import org.eclipse.cdt.core.settings.model.extension.CBuildData; import org.eclipse.cdt.core.settings.model.extension.CConfigurationData; import org.eclipse.cdt.managedbuilder.buildproperties.IBuildPropertyValue; +import org.eclipse.cdt.managedbuilder.buildproperties.IOptionalBuildProperties; import org.eclipse.cdt.managedbuilder.core.BuildException; import org.eclipse.cdt.managedbuilder.core.IBuildObjectProperties; import org.eclipse.cdt.managedbuilder.core.IBuilder; @@ -632,6 +633,13 @@ public class TestConfiguration implements IConfiguration { // TODO Auto-generated method stub return null; } + + @Override + public IOptionalBuildProperties getOptionalBuildProperties() { + // TODO Auto-generated method stub + return null; + } + @Override public IResource getOwner() { return null; } diff --git a/build/org.eclipse.cdt.managedbuilder.ui.tests/src/org/eclipse/cdt/managedbuilder/ui/tests/util/TestProjectType.java b/build/org.eclipse.cdt.managedbuilder.ui.tests/src/org/eclipse/cdt/managedbuilder/ui/tests/util/TestProjectType.java index d22f0878a6b..0727d3bdc73 100644 --- a/build/org.eclipse.cdt.managedbuilder.ui.tests/src/org/eclipse/cdt/managedbuilder/ui/tests/util/TestProjectType.java +++ b/build/org.eclipse.cdt.managedbuilder.ui.tests/src/org/eclipse/cdt/managedbuilder/ui/tests/util/TestProjectType.java @@ -11,6 +11,7 @@ package org.eclipse.cdt.managedbuilder.ui.tests.util; import org.eclipse.cdt.managedbuilder.buildproperties.IBuildPropertyValue; +import org.eclipse.cdt.managedbuilder.buildproperties.IOptionalBuildProperties; import org.eclipse.cdt.managedbuilder.core.IBuildObjectProperties; import org.eclipse.cdt.managedbuilder.core.IConfiguration; import org.eclipse.cdt.managedbuilder.core.IConfigurationNameProvider; @@ -76,6 +77,8 @@ public class TestProjectType implements IProjectType { public void setVersion(Version version) {} @Override public IBuildObjectProperties getBuildProperties() { return null; } + @Override + public IOptionalBuildProperties getOptionalBuildProperties() { return null; } @Override public IBuildPropertyValue getBuildArtefactType() { diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/externaltool/ExternalToolInvoker.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/externaltool/ExternalToolInvoker.java index 8343815c423..ba3de1969c0 100644 --- a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/externaltool/ExternalToolInvoker.java +++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/externaltool/ExternalToolInvoker.java @@ -18,7 +18,7 @@ import org.eclipse.cdt.codan.core.cxx.externaltool.ConfigurationSettings; import org.eclipse.cdt.codan.core.cxx.externaltool.InvocationFailure; import org.eclipse.cdt.codan.core.cxx.externaltool.InvocationParameters; import org.eclipse.cdt.core.CCorePlugin; -import org.eclipse.cdt.core.CommandLauncher; +import org.eclipse.cdt.core.CommandLauncherFactoryManager; import org.eclipse.cdt.core.ICommandLauncher; import org.eclipse.cdt.core.IConsoleParser; import org.eclipse.cdt.core.resources.IConsole; @@ -85,7 +85,7 @@ public class ExternalToolInvoker { final OutputStream out = sniffer.getOutputStream(); final OutputStream err = sniffer.getErrorStream(); try { - ICommandLauncher launcher = new CommandLauncher(); + ICommandLauncher launcher = CommandLauncherFactoryManager.getInstance().getCommandLauncher(); launcher.showCommand(true); launcher.setProject(project); Process p = launcher.execute(commandPath, commandArgs, commandEnv, workingDirectory, new SubProgressMonitor(monitor, 50)); diff --git a/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF b/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF index 3b39f4d4b15..cafe7f2bc14 100644 --- a/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF +++ b/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.cdt.core; singleton:=true -Bundle-Version: 6.3.1.qualifier +Bundle-Version: 6.3.0.qualifier Bundle-Activator: org.eclipse.cdt.core.CCorePlugin Bundle-Vendor: %providerName Bundle-Localization: plugin diff --git a/core/org.eclipse.cdt.core/plugin.xml b/core/org.eclipse.cdt.core/plugin.xml index 81354a3bcb3..086b08d5efe 100644 --- a/core/org.eclipse.cdt.core/plugin.xml +++ b/core/org.eclipse.cdt.core/plugin.xml @@ -692,6 +692,7 @@ + diff --git a/core/org.eclipse.cdt.core/schema/CommandLauncherFactory.exsd b/core/org.eclipse.cdt.core/schema/CommandLauncherFactory.exsd new file mode 100644 index 00000000000..272418d837b --- /dev/null +++ b/core/org.eclipse.cdt.core/schema/CommandLauncherFactory.exsd @@ -0,0 +1,122 @@ + + + + + + + + + This extension point is used to contribute a Command Launcher factory to CDT. A Command Launcher factory creates a Command Launcher for running commands. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Command Launcher factory class that implements org.eclipse.cdt.core.ICommandLauncherFactory. + + + + + + + + + + + + + + + CDT 9.3.0 + + + + + + + + + [Enter extension point usage example here.] + + + + + + + + + Plug-ins that want to extend this extension point must implement <samp>org.eclipse.cdt.core.ICommandLauncherFactory</samp> interface. + + + + + + + + + [Enter information about supplied implementation of this extension point.] + + + + + + + + + Copyright (c) 2017 Red Hat Inc. and others.<br/> +All rights reserved. This program and the accompanying materials<br/> +are made available under the terms of the Eclipse Public License v1.0<br/> +which accompanies this distribution, and is available at<br/> +http://www.eclipse.org/legal/epl-v10.html<br/> + + + + diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java index 6909c65f181..d4ca846574d 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java @@ -147,6 +147,17 @@ public class CCorePlugin extends Plugin { */ public static final String ERROR_PARSER_UNIQ_ID = PLUGIN_ID + "." + ERROR_PARSER_SIMPLE_ID; //$NON-NLS-1$ + /** + * Name of the extension point for contributing a Command Launcher factory + * @since 6.3 + */ + public static final String COMMAND_LAUNCHER_FACTORY_SIMPLE_ID = "CommandLauncherFactory"; //$NON-NLS-1$ + /** + * Full unique name of the extension point for contributing a Command Launcher factory + * @since 6.3 + */ + public static final String COMMAND_LAUNCHER_FACTORY_UNIQ_ID = PLUGIN_ID + "." + COMMAND_LAUNCHER_FACTORY_SIMPLE_ID; //$NON-NLS-1$ + // default store for pathentry public static final String DEFAULT_PATHENTRY_STORE_ID = PLUGIN_ID + ".cdtPathEntryStore"; //$NON-NLS-1$ diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CommandLauncherFactoryManager.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CommandLauncherFactoryManager.java new file mode 100644 index 00000000000..cac12d153d5 --- /dev/null +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CommandLauncherFactoryManager.java @@ -0,0 +1,206 @@ +/******************************************************************************* + * Copyright (c) 2017 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 API and implementation + *******************************************************************************/ +package org.eclipse.cdt.core; + +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtension; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.IExtensionRegistry; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Platform; + +/** + * @since 6.3 + */ +public class CommandLauncherFactoryManager { + + private static CommandLauncherFactoryManager instance; + + private List factories = new ArrayList<>(); + + private CommandLauncherFactoryManager() { + loadCommandLauncherFactoryExtensions(); + } + + public static synchronized CommandLauncherFactoryManager getInstance() { + if (instance == null) { + instance = new CommandLauncherFactoryManager(); + } + return instance; + } + + public ICommandLauncher getCommandLauncher() { + return new CommandLauncherWrapper(this); + } + + + private class CommandLauncherWrapper implements ICommandLauncher { + + private ICommandLauncher launcher; + private IProject fProject; + private boolean fShowCommand; + private String fErrorMessage; + private CommandLauncherFactoryManager manager; + + public CommandLauncherWrapper(CommandLauncherFactoryManager manager) { + this.manager = manager; + } + + @Override + public void setProject(IProject project) { + if (launcher != null) { + launcher.setProject(project); + } else { + fProject = project; + } + } + + @Override + public IProject getProject() { + if (launcher != null) { + return launcher.getProject(); + } + return fProject; + } + + @Override + public void showCommand(boolean show) { + if (launcher != null) { + launcher.showCommand(show); + } else { + fShowCommand = show; + } + } + + @Override + public String getErrorMessage() { + if (launcher != null) { + return launcher.getErrorMessage(); + } + return fErrorMessage; + } + + @Override + public void setErrorMessage(String error) { + if (launcher != null) { + launcher.setErrorMessage(error); + } else { + fErrorMessage = error; + } + } + + @Override + public String[] getCommandArgs() { + if (launcher != null) { + return launcher.getCommandArgs(); + } + return new String[0]; + } + + @Override + public Properties getEnvironment() { + if (launcher != null) { + return launcher.getEnvironment(); + } + return null; + } + + @Override + public String getCommandLine() { + if (launcher != null) { + return launcher.getCommandLine(); + } + return null; + } + + @Override + public Process execute(IPath commandPath, String[] args, String[] env, IPath workingDirectory, + IProgressMonitor monitor) throws CoreException { + if (launcher == null) { + launcher = manager.getCommandLauncher(fProject); + launcher.setProject(fProject); + launcher.showCommand(fShowCommand); + launcher.setErrorMessage(fErrorMessage); + } + return launcher.execute(commandPath, args, env, workingDirectory, monitor); + } + + @Override + public int waitAndRead(OutputStream out, OutputStream err) { + if (launcher != null) { + return launcher.waitAndRead(out, err); + } + return 0; + } + + @Override + public int waitAndRead(OutputStream output, OutputStream err, IProgressMonitor monitor) { + if (launcher != null) { + return launcher.waitAndRead(output, err, monitor); + } + return 0; + } + + } + /** + * Get a command launcher. + * + * @param project - optional input to determine launcher. + * @return an ICommandLauncher for running commands + */ + public ICommandLauncher getCommandLauncher(IProject project) { + // loop through list of factories and return first launcher + // returned + for (ICommandLauncherFactory factory : factories) { + ICommandLauncher launcher = factory.getCommandLauncher(project); + if (launcher != null) { + return launcher; + } + } + // default to local CommandLauncher + return new CommandLauncher(); + } + + /** + * Load command launcher factory contributed extensions from extension registry. + * + */ + private void loadCommandLauncherFactoryExtensions() { + IExtensionRegistry registry = Platform.getExtensionRegistry(); + IExtensionPoint extension = registry.getExtensionPoint(CCorePlugin.PLUGIN_ID, CCorePlugin.COMMAND_LAUNCHER_FACTORY_SIMPLE_ID); + if (extension != null) { + IExtension[] extensions = extension.getExtensions(); + for (IExtension ext : extensions) { + try { + IConfigurationElement element[] = extension.getConfigurationElements(); + for (IConfigurationElement element2 : element) { + if (element2.getName().equalsIgnoreCase("cextension")) { //$NON-NLS-1$ + ICommandLauncherFactory factory = (ICommandLauncherFactory) element2.createExecutableExtension("run"); //$NON-NLS-1$ + factories.add(factory); + } + } + } catch (Exception e) { + CCorePlugin.log("Cannot load CommandLauncherFactory extension " + ext.getUniqueIdentifier(), e); //$NON-NLS-1$ + } + } + } + } + + +} diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICommandLauncherFactory.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICommandLauncherFactory.java new file mode 100644 index 00000000000..29855a9d8e3 --- /dev/null +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICommandLauncherFactory.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2017 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 API and implementation + *******************************************************************************/ +package org.eclipse.cdt.core; + +import org.eclipse.core.resources.IProject; + +/** + * @since 6.3 + */ +public interface ICommandLauncherFactory { + + /** + * Get a Command Launcher for a project (optional) + * @param project - optional parameter to help determine appropriate launcher + * @return ICommandLauncher or null if not appropriate for project + */ + public ICommandLauncher getCommandLauncher(IProject project); + +} diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/ProcessClosure.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/ProcessClosure.java index 771cb6e4b0b..668457e1d75 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/ProcessClosure.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/ProcessClosure.java @@ -217,14 +217,18 @@ public class ProcessClosure { fProcess.destroy(); fProcess = null; } - if (!fOutputReader.finished()) { - fOutputReader.waitFor(); + if (fOutputReader != null) { + if (!fOutputReader.finished()) { + fOutputReader.waitFor(); + } + fOutputReader.close(); } - if (!fErrorReader.finished()) { - fErrorReader.waitFor(); + if (fErrorReader != null) { + if (!fErrorReader.finished()) { + fErrorReader.waitFor(); + } + fErrorReader.close(); } - fOutputReader.close(); - fErrorReader.close(); fOutputReader = null; fErrorReader = null; } 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 c24f2f49390..964621fbfa4 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.0.0.qualifier +Bundle-Version: 1.1.0.qualifier Bundle-Activator: org.eclipse.cdt.docker.launcher.DockerLaunchUIPlugin Bundle-Vendor: %Plugin.vendor Bundle-Localization: plugin @@ -20,7 +20,9 @@ Require-Bundle: org.eclipse.ui, org.eclipse.cdt.debug.ui;bundle-version="7.5.0", org.eclipse.cdt.dsf.gdb;bundle-version="4.6.0", org.eclipse.cdt.dsf.gdb.ui;bundle-version="2.4.0", - org.eclipse.core.variables + org.eclipse.core.variables, + org.eclipse.cdt.managedbuilder.ui, + org.eclipse.cdt.managedbuilder.core Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-ActivationPolicy: lazy Export-Package: org.eclipse.cdt.docker.launcher;x-internal:=true, diff --git a/launch/org.eclipse.cdt.docker.launcher/plugin.properties b/launch/org.eclipse.cdt.docker.launcher/plugin.properties index 0669aa80aad..aae650077a0 100644 --- a/launch/org.eclipse.cdt.docker.launcher/plugin.properties +++ b/launch/org.eclipse.cdt.docker.launcher/plugin.properties @@ -16,3 +16,8 @@ must be set-up to supply the C/C++ application what it needs to run. LaunchConfigurationType.name=C/C++ Container Launcher Shortcut.label=C/C++ Container Application DockerLaunchPreferencePage.name=Docker Container Launch +ContainerCommandLauncherFactory.name=Container Command Launcher Factory +Container.settings=Container Settings +ContainerBuild.property.enablement=Container Build Enablement +ContainerBuild.property.connection=Container Build Connection +ContainerBuild.property.image=Container Build Image diff --git a/launch/org.eclipse.cdt.docker.launcher/plugin.xml b/launch/org.eclipse.cdt.docker.launcher/plugin.xml index a8e0a2cdb82..48250b94186 100644 --- a/launch/org.eclipse.cdt.docker.launcher/plugin.xml +++ b/launch/org.eclipse.cdt.docker.launcher/plugin.xml @@ -88,5 +88,25 @@ id="org.eclipse.cdt.docker.launcher.launchConfigurationTypeImage1"> - + + + + + + + + + + + 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 new file mode 100644 index 00000000000..c19724f9e92 --- /dev/null +++ b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/docker/launcher/ContainerCommandLauncherFactory.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2017 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 API and implementation + *******************************************************************************/ +package org.eclipse.cdt.docker.launcher; + +import org.eclipse.cdt.core.ICommandLauncher; +import org.eclipse.cdt.core.ICommandLauncherFactory; +import org.eclipse.cdt.core.model.CoreModel; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.internal.docker.launcher.ContainerCommandLauncher; +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; + +public class ContainerCommandLauncherFactory + implements ICommandLauncherFactory { + + @Override + public ICommandLauncher getCommandLauncher(IProject project) { + // check if container build enablement has been checked + 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); + // enablement has occurred, we can return a + // ContainerCommandLauncher + if (enableContainer) { + return new ContainerCommandLauncher(); + } + } + } + return null; + } + +} diff --git a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ContainerCommandLauncher.java b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ContainerCommandLauncher.java new file mode 100644 index 00000000000..660d0baf3d1 --- /dev/null +++ b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ContainerCommandLauncher.java @@ -0,0 +1,353 @@ +package org.eclipse.cdt.internal.docker.launcher; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.eclipse.cdt.core.ICommandLauncher; +import org.eclipse.cdt.core.model.CoreModel; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.docker.launcher.DockerLaunchUIPlugin; +import org.eclipse.cdt.internal.core.ProcessClosure; +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.IProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.eclipse.core.variables.VariablesPlugin; +import org.eclipse.linuxtools.docker.ui.launch.ContainerLauncher; +import org.eclipse.linuxtools.docker.ui.launch.IErrorMessageHolder; +import org.eclipse.linuxtools.internal.docker.ui.launch.ContainerCommandProcess; +import org.eclipse.osgi.util.NLS; +import org.osgi.service.prefs.Preferences; + +@SuppressWarnings("restriction") +public class ContainerCommandLauncher + implements ICommandLauncher, IErrorMessageHolder { + + public final static String CONTAINER_BUILD_ENABLED = "org.eclipse.cdt.docker.launcher.containerbuild.property.enablement"; // $NON-NLS-0$ + public final static String CONNECTION_ID = "org.eclipse.cdt.docker.launcher.containerbuild.property.connection"; // $NON-NLS-0$ + public final static String IMAGE_ID = "org.eclipse.cdt.docker.launcher.containerbuild.property.image"; // $NON-NLS-0$ + + private IProject fProject; + private Process fProcess; + private boolean fShowCommand; + private String fErrorMessage; + private Properties fEnvironment; + + private String[] commandArgs; + private String fImageName = ""; //$NON-NLS-1$ + + public final static int COMMAND_CANCELED = ICommandLauncher.COMMAND_CANCELED; + public final static int ILLEGAL_COMMAND = ICommandLauncher.ILLEGAL_COMMAND; + public final static int OK = ICommandLauncher.OK; + + private static final String NEWLINE = System.getProperty("line.separator", //$NON-NLS-1$ + "\n"); //$NON-NLS-1$ + + /** + * The number of milliseconds to pause between polling. + */ + protected static final long DELAY = 50L; + + @Override + public void setProject(IProject project) { + this.fProject = project; + } + + @Override + public IProject getProject() { + return fProject; + } + + private String getImageName() { + return fImageName; + } + + private void setImageName(String imageName) { + fImageName = imageName; + } + + @Override + public void showCommand(boolean show) { + this.fShowCommand = show; + } + + @Override + public String getErrorMessage() { + return fErrorMessage; + } + + @Override + public void setErrorMessage(String error) { + fErrorMessage = error; + } + + @Override + public String[] getCommandArgs() { + return commandArgs; + } + + @Override + public Properties getEnvironment() { + return fEnvironment; + } + + @Override + public String getCommandLine() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Process execute(IPath commandPath, String[] args, String[] env, + IPath workingDirectory, IProgressMonitor monitor) + throws CoreException { + + HashMap labels = new HashMap<>(); + labels.put("org.eclipse.cdt.container-command", ""); //$NON-NLS-1$ //$NON-NLS-2$ + String projectName = fProject.getName(); + labels.put("org.eclipse.cdt.project-name", projectName); //$NON-NLS-1$ + + List additionalDirs = new ArrayList<>(); + + ArrayList commandSegments = new ArrayList<>(); + + StringBuilder b = new StringBuilder(); + b.append(commandPath.toString().trim()); + commandSegments.add(commandPath.toString().trim()); + for (String arg : args) { + b.append(" "); //$NON-NLS-1$ + String realArg = VariablesPlugin.getDefault() + .getStringVariableManager().performStringSubstitution(arg); + b.append(realArg); + if (realArg.startsWith("/")) { //$NON-NLS-1$ + // check if file exists and if so, add an additional directory + IPath p = new Path(realArg); + if (p.isValidPath(realArg)) { + p = p.makeAbsolute(); + File f = p.toFile(); + if (f.exists()) { + if (f.isFile()) { + p = p.removeLastSegments(1); + } + additionalDirs.add(p.toPortableString()); + } + } + } + commandSegments.add(realArg); + } + + commandArgs = commandSegments.toArray(new String[0]); + + String commandDir = commandPath.removeLastSegments(1).toString(); + if (commandDir.isEmpty()) { + commandDir = null; + } + + IProject[] referencedProjects = fProject.getReferencedProjects(); + for (IProject referencedProject : referencedProjects) { + additionalDirs + .add(referencedProject.getLocation().toPortableString()); + } + + String command = b.toString(); + + String workingDir = workingDirectory.toPortableString(); + parseEnvironment(env); + Map origEnv = null; + + boolean supportStdin = false; + + boolean privilegedMode = false; + + ContainerLauncher launcher = new ContainerLauncher(); + + Preferences prefs = InstanceScope.INSTANCE + .getNode(DockerLaunchUIPlugin.PLUGIN_ID); + + boolean keepContainer = prefs.getBoolean( + PreferenceConstants.KEEP_CONTAINER_AFTER_LAUNCH, false); + + ICConfigurationDescription cfgd = CoreModel.getDefault() + .getProjectDescription(fProject).getActiveConfiguration(); + IConfiguration cfg = ManagedBuildManager + .getConfigurationForDescription(cfgd); + if (cfg == null) { + return null; + } + IOptionalBuildProperties props = cfg.getOptionalBuildProperties(); + String connectionName = props + .getProperty(ContainerCommandLauncher.CONNECTION_ID); + if (connectionName == null) { + return null; + } + String imageName = props + .getProperty(ContainerCommandLauncher.IMAGE_ID); + if (imageName == null) { + return null; + } + setImageName(imageName); + + fProcess = launcher.runCommand(connectionName, imageName, fProject, + this, + command, + commandDir, + workingDir, + additionalDirs, + origEnv, fEnvironment, supportStdin, privilegedMode, + labels, keepContainer); + + return fProcess; + } + + /** + * Parse array of "ENV=value" pairs to Properties. + */ + private void parseEnvironment(String[] env) { + fEnvironment = null; + if (env != null) { + fEnvironment = new Properties(); + for (String envStr : env) { + // Split "ENV=value" and put in Properties + int pos = envStr.indexOf('='); // $NON-NLS-1$ + if (pos < 0) + pos = envStr.length(); + String key = envStr.substring(0, pos); + String value = envStr.substring(pos + 1); + fEnvironment.put(key, value); + } + } + } + + @Override + public int waitAndRead(OutputStream out, OutputStream err) { + printImageHeader(out); + + if (fShowCommand) { + printCommandLine(out); + } + + if (fProcess == null) { + return ILLEGAL_COMMAND; + } + ProcessClosure closure = new ProcessClosure(fProcess, out, err); + closure.runBlocking(); // a blocking call + return OK; + } + + @Override + public int waitAndRead(OutputStream output, OutputStream err, + IProgressMonitor monitor) { + printImageHeader(output); + + if (fShowCommand) { + printCommandLine(output); + } + + if (fProcess == null) { + return ILLEGAL_COMMAND; + } + + ProcessClosure closure = new ProcessClosure(fProcess, output, err); + closure.runNonBlocking(); + Runnable watchProcess = () -> { + try { + fProcess.waitFor(); + } catch (InterruptedException e) { + // ignore + } + closure.terminate(); + }; + Thread t = new Thread(watchProcess); + t.start(); + while (!monitor.isCanceled() && closure.isAlive()) { + try { + Thread.sleep(DELAY); + } catch (InterruptedException ie) { + break; + } + } + try { + t.join(500); + } catch (InterruptedException e1) { + // ignore + } + int state = OK; + + // Operation canceled by the user, terminate abnormally. + if (monitor.isCanceled()) { + closure.terminate(); + state = COMMAND_CANCELED; + setErrorMessage(Messages.CommandLauncher_CommandCancelled); + } + try { + fProcess.waitFor(); + } catch (InterruptedException e) { + // ignore + } + + monitor.done(); + return state; + } + + protected void printImageHeader(OutputStream os) { + if (os != null) { + try { + os.write(NLS + .bind(Messages.ContainerCommandLauncher_image_msg, + ((ContainerCommandProcess) fProcess).getImage()) + .getBytes()); + os.write(NEWLINE.getBytes()); + os.flush(); + } catch (IOException e) { + // ignore + } + } + } + + protected void printCommandLine(OutputStream os) { + if (os != null) { + try { + os.write(getCommandLineQuoted(getCommandArgs(), true) + .getBytes()); + os.flush(); + } catch (IOException e) { + // ignore; + } + } + } + + @SuppressWarnings("nls") + private String getCommandLineQuoted(String[] commandArgs, boolean quote) { + StringBuilder buf = new StringBuilder(); + if (commandArgs != null) { + for (String commandArg : commandArgs) { + if (quote && (commandArg.contains(" ") + || commandArg.contains("\"") + || commandArg.contains("\\"))) { + commandArg = '"' + commandArg.replaceAll("\\\\", "\\\\\\\\") + .replaceAll("\"", "\\\\\"") + '"'; + } + buf.append(commandArg); + buf.append(' '); + } + buf.append(NEWLINE); + } + return buf.toString(); + } + + protected String getCommandLine(String[] commandArgs) { + return getCommandLineQuoted(commandArgs, false); + } + +} 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 4f74b99ab7d..d0f14f22c8b 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 @@ -79,7 +79,8 @@ public class ContainerLaunchConfigurationDelegate extends GdbLaunchDelegate @Override public void newOutput(String output) { - if (output.contains(Messages.Gdbserver_up)) { + if (output.contains(Messages.Gdbserver_up) + || output.contains("gdbserver:")) { //$NON-NLS-1$ started = true; } diff --git a/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ContainerPropertyTab.java b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ContainerPropertyTab.java new file mode 100644 index 00000000000..d6dc7d4180a --- /dev/null +++ b/launch/org.eclipse.cdt.docker.launcher/src/org/eclipse/cdt/internal/docker/launcher/ContainerPropertyTab.java @@ -0,0 +1,428 @@ +/******************************************************************************* + * Copyright (c) 2017 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 API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.docker.launcher; + +import java.util.ArrayList; + +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICMultiConfigDescription; +import org.eclipse.cdt.core.settings.model.ICResourceDescription; +import org.eclipse.cdt.managedbuilder.buildproperties.IOptionalBuildProperties; +import org.eclipse.cdt.managedbuilder.core.IConfiguration; +import org.eclipse.cdt.managedbuilder.core.IMultiConfiguration; +import org.eclipse.cdt.managedbuilder.internal.core.Configuration; +import org.eclipse.cdt.managedbuilder.ui.properties.AbstractCBuildPropertyTab; +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.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; + +@SuppressWarnings("restriction") +public class ContainerPropertyTab extends AbstractCBuildPropertyTab + implements IDockerConnectionManagerListener, IDockerImageListener { + + private Combo imageCombo; + private Combo connectionSelector; + private Button enableButton; + + private IDockerConnection connection; + private IDockerConnection[] connections; + private IDockerImageListener containerTab; + + private String connectionName; + private String connectionUri = ""; //$NON-NLS-1$ + + private boolean defaultEnabled; + private String defaultConnection; + private String defaultImage; + + private IConfiguration iCfg; + private IOptionalBuildProperties properties; + + private ModifyListener connectionModifyListener = new ModifyListener() { + + @Override + public void modifyText(ModifyEvent e) { + int index = connectionSelector.getSelectionIndex(); + if (connection != null) + connection.removeImageListener(containerTab); + connection = connections[index]; + connectionUri = connection.getUri(); + if (!connectionName.equals(connection.getName())) { + imageCombo.setText(""); + defaultImage = null; + } + connectionName = connection.getName(); + properties.setProperty(ContainerCommandLauncher.CONNECTION_ID, + connectionUri); + properties.setProperty(ContainerCommandLauncher.IMAGE_ID, + imageCombo.getText()); + } + + }; + + public ContainerPropertyTab() { + this.containerTab = this; + } + + @Override + public void createControls(Composite parent) { + super.createControls(parent); + + usercomp.setLayout(new GridLayout(5, false)); + usercomp.setFont(parent.getFont()); + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalSpan = 1; + + usercomp.setLayoutData(gd); + + enableButton = new Button(usercomp, SWT.CHECK); + enableButton.setText(Messages.ContainerPropertyTab_Enable_Msg); + + iCfg = getCfg(); + properties = iCfg.getOptionalBuildProperties(); + + gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalSpan = 5; + enableButton.setLayoutData(gd); + + Label connectionSelectorLabel = new Label(usercomp, SWT.NULL); + connectionSelectorLabel + .setText(Messages.ContainerTab_Connection_Selector_Label); + gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalSpan = 1; + gd.grabExcessHorizontalSpace = false; + connectionSelectorLabel.setLayoutData(gd); + + connectionSelector = new Combo(usercomp, SWT.BORDER | SWT.READ_ONLY); + initializeConnectionSelector(iCfg); + 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; + } + }); + gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalSpan = 4; + gd.grabExcessHorizontalSpace = true; + connectionSelector.setLayoutData(gd); + + Label imageSelectorLabel = new Label(usercomp, SWT.NULL); + imageSelectorLabel.setText(Messages.ContainerTab_Image_Selector_Label); + gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalSpan = 1; + connectionSelectorLabel.setLayoutData(gd); + + imageCombo = new Combo(usercomp, SWT.DROP_DOWN); + gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalSpan = 4; + gd.grabExcessHorizontalSpace = true; + imageCombo.setLayoutData(gd); + + initializeImageCombo(iCfg); + + imageCombo.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + properties.setProperty(ContainerCommandLauncher.IMAGE_ID, + imageCombo.getText()); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + } + + }); + + initializeEnablementButton(iCfg); + enableButton.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + setControlsEnabled(enableButton.getSelection()); + properties.setProperty( + ContainerCommandLauncher.CONTAINER_BUILD_ENABLED, + Boolean.toString(enableButton.getSelection())); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + // ignore + } + + }); + + } + + private void setControlsEnabled(boolean enabled) { + imageCombo.setEnabled(enabled); + connectionSelector.setEnabled(enabled); + } + + private void initializeEnablementButton(IConfiguration cfg) { + defaultEnabled = false; + IOptionalBuildProperties properties = cfg.getOptionalBuildProperties(); + String savedEnabled = properties + .getProperty(ContainerCommandLauncher.CONTAINER_BUILD_ENABLED); + if (savedEnabled != null) { + defaultEnabled = Boolean + .parseBoolean(savedEnabled); + } + enableButton.setSelection(defaultEnabled); + setControlsEnabled(defaultEnabled); + } + + private void initializeConnectionSelector(IConfiguration cfg) { + int defaultIndex = -1; + defaultConnection = null; + String id = properties + .getProperty(ContainerCommandLauncher.CONNECTION_ID); + if (id != null) { + defaultConnection = id; + } + connections = DockerConnectionManager.getInstance().getConnections(); + if (connections.length == 0) { + // setErrorMessage(Messages.ContainerTab_Error_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(defaultConnection)) + defaultIndex = i; + } + if (defaultIndex < 0) { + defaultEnabled = false; + defaultIndex = 0; + } + connectionSelector.setItems(connectionNames); + if (connections.length > 0) { + connectionSelector.select(defaultIndex); + connection = connections[defaultIndex]; + connectionName = connection.getName(); + connectionUri = connection.getUri(); + defaultConnection = connectionUri; + } + } + + private void initializeImageCombo(IConfiguration cfg) { + defaultImage = null; + String id = properties + .getProperty(ContainerCommandLauncher.IMAGE_ID); + if (id != null) { + defaultImage = id; + } + if (connection != null) { + java.util.List images = connection.getImages(); + if (images == null || images.size() == 0) { + // setsetErrorMessage(Messages.ContainerTab_Error_No_Images); + return; + } + connection.removeImageListener(containerTab); + 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 (defaultImage != null) { + int index = imageCombo.indexOf(defaultImage); + if (index > -1) { + imageCombo.getItem(index); + imageCombo.select(index); + } else { + } + } + connection.addImageListener(containerTab); + } + } + + @Override + protected void performApply(ICResourceDescription src, + ICResourceDescription dst) { + if (page.isMultiCfg()) { + ICMultiConfigDescription mc1 = (ICMultiConfigDescription) src + .getConfiguration(); + ICMultiConfigDescription mc2 = (ICMultiConfigDescription) dst + .getConfiguration(); + ICConfigurationDescription[] cds1 = (ICConfigurationDescription[]) mc1 + .getItems(); + ICConfigurationDescription[] cds2 = (ICConfigurationDescription[]) mc2 + .getItems(); + for (int i = 0; i < cds1.length; i++) + applyToCfg(cds1[i], cds2[i]); + } else + applyToCfg(src.getConfiguration(), dst.getConfiguration()); + + } + + private void applyToCfg(ICConfigurationDescription c1, + ICConfigurationDescription c2) { + Configuration cfg01 = (Configuration) getCfg(c1); + Configuration cfg02 = (Configuration) getCfg(c2); + IOptionalBuildProperties prop1 = cfg01.getOptionalBuildProperties(); + IOptionalBuildProperties prop2 = cfg02.getOptionalBuildProperties(); + String enablementProperty = prop1 + .getProperty(ContainerCommandLauncher.CONTAINER_BUILD_ENABLED); + prop2.setProperty(ContainerCommandLauncher.CONTAINER_BUILD_ENABLED, + enablementProperty); + String connectionProperty = prop1 + .getProperty(ContainerCommandLauncher.CONNECTION_ID); + prop2.setProperty(ContainerCommandLauncher.CONNECTION_ID, + connectionProperty); + String imageProperty = prop1 + .getProperty(ContainerCommandLauncher.IMAGE_ID); + prop2.setProperty(ContainerCommandLauncher.IMAGE_ID, imageProperty); + } + + + @Override + protected void performDefaults() { + if (iCfg instanceof IMultiConfiguration) { + IConfiguration[] cfs = (IConfiguration[]) ((IMultiConfiguration) iCfg) + .getItems(); + for (int i = 0; i < cfs.length; i++) { + IOptionalBuildProperties props = cfs[i] + .getOptionalBuildProperties(); + props.setProperty( + ContainerCommandLauncher.CONTAINER_BUILD_ENABLED, + Boolean.toString(false)); + if (connections.length > 0) { + props.setProperty(ContainerCommandLauncher.CONNECTION_ID, + connections[0].getUri()); + } else { + props.setProperty(ContainerCommandLauncher.CONNECTION_ID, + null); + } + props.setProperty(ContainerCommandLauncher.IMAGE_ID, null); + } + } else { + IOptionalBuildProperties props = iCfg.getOptionalBuildProperties(); + props.setProperty(ContainerCommandLauncher.CONTAINER_BUILD_ENABLED, + Boolean.toString(false)); + if (connections.length > 0) { + props.setProperty(ContainerCommandLauncher.CONNECTION_ID, + connections[0].getUri()); + } else { + props.setProperty(ContainerCommandLauncher.CONNECTION_ID, null); + } + props.setProperty(ContainerCommandLauncher.IMAGE_ID, null); + } + defaultEnabled = false; + if (connections.length > 0) { + connectionSelector.select(0); + } + imageCombo.setText(""); //$NON-NLS-1$ + enableButton.setSelection(false); + setControlsEnabled(false); + } + + @Override + public void updateData(ICResourceDescription cfgd) { + if (cfgd == null) + return; + iCfg = getCfg(cfgd.getConfiguration()); + initializeConnectionSelector(iCfg); + initializeImageCombo(iCfg); + initializeEnablementButton(iCfg); + } + + @Override + protected void updateButtons() { + // TODO Auto-generated method stub + + } + + @Override + public void changeEvent(int type) { + String currUri = null; + int currIndex = 0; + 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(); + } else { + connection = null; + connectionUri = ""; + connectionSelector.setText(""); + } + connectionSelector.addModifyListener(connectionModifyListener); + } + + @Override + public void listChanged(IDockerConnection c, + java.util.List list) { + final IDockerImage[] finalList = list.toArray(new IDockerImage[0]); + if (c.getName().equals(connection.getName())) { + Display.getDefault().syncExec(new Runnable() { + @Override + public void run() { + connection.removeImageListener(containerTab); + 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(containerTab); + } + + }); + } + } + +} 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 ed716c3361f..5ad81d2dcde 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 @@ -19,13 +19,18 @@ import org.eclipse.cdt.core.model.CModelException; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.IBinary; import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.debug.core.CDebugUtils; import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; import org.eclipse.cdt.docker.launcher.DockerLaunchUIPlugin; 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.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.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; @@ -253,6 +258,31 @@ public class LaunchShortcut implements ILaunchShortcut { ILaunchConfiguration configuration = null; 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); + } + } + } + } try { ILaunchConfiguration[] configs = DebugPlugin.getDefault() .getLaunchManager().getLaunchConfigurations(configType); @@ -265,7 +295,17 @@ public class LaunchShortcut implements ILaunchShortcut { if (projectName != null && projectName.equals(bin.getCProject() .getProject().getName())) { - candidateConfigs.add(config); + // if we have an active configuration with container + // build properties, make sure they match, otherwise + // add the launch config as a candidate + if (connectionUri.equals(config.getAttribute( + ILaunchConstants.ATTR_CONNECTION_URI, + connectionUri))) { + if (imageName.equals(config.getAttribute( + ILaunchConstants.ATTR_IMAGE, imageName))) { + candidateConfigs.add(config); + } + } } } } @@ -312,11 +352,40 @@ public class LaunchShortcut implements ILaunchShortcut { 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; + + 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); + } + } + ILaunchConfigurationType configType = getLaunchConfigType(); ILaunchConfigurationWorkingCopy wc = configType.newInstance( null, getLaunchManager().generateLaunchConfigurationName( - bin.getElementName())); + bin.getResource().getName() + (imageName != null + ? ("[" + imageName + "]") //$NON-NLS-1$ //$NON-NLS-2$ + : ""))); //$NON-NLS-1$ // DSF settings...use GdbUIPlugin preference store for defaults IPreferenceStore preferenceStore = GdbUIPlugin.getDefault() @@ -357,19 +426,25 @@ public class LaunchShortcut implements ILaunchShortcut { Preferences prefs = InstanceScope.INSTANCE .getNode(DockerLaunchUIPlugin.PLUGIN_ID); - // get the connection from the ConnectionListener which waits for - // any activity - // from the DockerExplorerView - IDockerConnection connection = ConnectionListener.getInstance() + // get the connection using following order: + // 1. connection used in build of project + // 2. current connection + // 3. first connection + IDockerConnection connection = null; + if (connectionId != null) { + connection = DockerConnectionManager.getInstance() + .getConnectionByUri(connectionId); + } + if (connection == null) { + connection = ConnectionListener.getInstance() .getCurrentConnection(); + } if (connection == null) { IDockerConnection[] connections = DockerConnectionManager .getInstance().getConnections(); if (connections != null && connections.length > 0) - connection = DockerConnectionManager.getInstance() - .getConnections()[0]; + connection = connections[0]; } - // issue error message if no connections exist if (connection == null) { Display.getDefault().syncExec(new Runnable() { @@ -389,9 +464,14 @@ public class LaunchShortcut implements ILaunchShortcut { wc.setAttribute(ILaunchConstants.ATTR_CONNECTION_URI, connection.getUri()); - // get any default image if specified, otherwise use first + // use build image if one is specified, otherwise, see if a default + // image is set in preferences, otherwise find first image in image + // list // image in image list for connection - String image = prefs.get(PreferenceConstants.DEFAULT_IMAGE, null); + String image = imageName; + if (image == null) { + image = prefs.get(PreferenceConstants.DEFAULT_IMAGE, null); + } if (image == null) { List images = connection.getImages(); if (images != null && images.size() > 0) 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 f3d6003d8a1..447f745a9a1 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 @@ -90,6 +90,12 @@ public class Messages extends NLS { public static String StandardGDBDebuggerPage14; + public static String ContainerPropertyTab_Title; + public static String ContainerPropertyTab_Enable_Msg; + + public static String ContainerCommandLauncher_image_msg; + public static String CommandLauncher_CommandCancelled; + static { // initialize resource bundle NLS.initializeMessages(BUNDLE_NAME, Messages.class); 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 15e1b19a0c7..7f06d56a2ff 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 @@ -40,6 +40,13 @@ ContainerTab_Error_No_Images=No Docker Images exist ContainerTab_Warning_Connection_Not_Found=Docker Connection: {0} for Launch Configuration not found: defaulting to {1} ContainerTab_Warning_Image_Not_Found=Docker Image: {0} is not a valid pulled image in current Connection: {1} +ContainerPropertyTab_Title=Container Settings +ContainerPropertyTab_Enable_Msg=Build inside Docker Image + +ContainerCommandLauncher_image_msg=[Running in image <{0}>] + +CommandLauncher_CommandCancelled=Command cancelled + Remote_GDB_Debugger_Options=Docker Container GDB Debugger Options Gdbserver_Settings_Tab_Name=Gdbserver Settings Gdbserver_name_textfield_label=Gdbserver path: diff --git a/remote/org.eclipse.cdt.remote.core/src/org/eclipse/cdt/remote/core/RemoteCommandLauncher.java b/remote/org.eclipse.cdt.remote.core/src/org/eclipse/cdt/remote/core/RemoteCommandLauncher.java index 85546854402..cfe9c89057e 100644 --- a/remote/org.eclipse.cdt.remote.core/src/org/eclipse/cdt/remote/core/RemoteCommandLauncher.java +++ b/remote/org.eclipse.cdt.remote.core/src/org/eclipse/cdt/remote/core/RemoteCommandLauncher.java @@ -17,7 +17,7 @@ import java.net.URI; import java.util.Map; import java.util.Properties; -import org.eclipse.cdt.core.CommandLauncher; +import org.eclipse.cdt.core.CommandLauncherFactoryManager; import org.eclipse.cdt.core.ICommandLauncher; import org.eclipse.cdt.remote.internal.core.Activator; import org.eclipse.cdt.remote.internal.core.messages.Messages; @@ -40,6 +40,8 @@ import org.eclipse.remote.core.RemoteProcessAdapter; public class RemoteCommandLauncher implements ICommandLauncher { private static final String CYGWIN_PREFIX = "cygdrive"; //$NON-NLS-1$ + + private boolean usingLocalLauncher = false; /** * Convert a local (workspace) path into the remote equivalent. If the local path is not @@ -102,7 +104,7 @@ public class RemoteCommandLauncher implements ICommandLauncher { return s; } - private final ICommandLauncher fLocalLauncher = new CommandLauncher(); + private ICommandLauncher fLocalLauncher = CommandLauncherFactoryManager.getInstance().getCommandLauncher(); private boolean fShowCommand; private String[] fCommandArgs; private IRemoteConnection fConnection; @@ -129,13 +131,18 @@ public class RemoteCommandLauncher implements ICommandLauncher { @Override public Process execute(IPath commandPath, String[] args, String[] env, IPath workingDirectory, IProgressMonitor monitor) throws CoreException { + ICommandLauncher localLauncher = CommandLauncherFactoryManager.getInstance().getCommandLauncher(getProject()); + localLauncher.setProject(getProject()); + localLauncher.setErrorMessage(getErrorMessage()); + usingLocalLauncher = false; + fLocalLauncher = localLauncher; if (getProject() != null) { IRemoteResource remRes = (IRemoteResource) getProject().getAdapter(IRemoteResource.class); if (remRes != null) { URI uri = remRes.getActiveLocationURI(); IRemoteServicesManager remoteServicesManager = Activator.getService(IRemoteServicesManager.class); IRemoteConnectionType connectionType = remoteServicesManager.getConnectionType(uri); - if (connectionType != null) { + if (connectionType != null && !connectionType.getScheme().equals("file")) { //$NON-NLS-1$ fConnection = connectionType.getConnection(uri); if (fConnection != null) { parseEnvironment(env); @@ -163,16 +170,23 @@ public class RemoteCommandLauncher implements ICommandLauncher { } } } + usingLocalLauncher = true; return fLocalLauncher.execute(commandPath, args, env, workingDirectory, monitor); } @Override public String[] getCommandArgs() { + if (usingLocalLauncher) { + return fLocalLauncher.getCommandArgs(); + } return fCommandArgs; } @Override public String getCommandLine() { + if (usingLocalLauncher) { + return fLocalLauncher.getCommandLine(); + } return getCommandLine(fCommandArgs); } @@ -202,6 +216,9 @@ public class RemoteCommandLauncher implements ICommandLauncher { @Override public Properties getEnvironment() { + if (usingLocalLauncher) { + return fLocalLauncher.getEnvironment(); + } return fEnvironment; } @@ -261,8 +278,15 @@ public class RemoteCommandLauncher implements ICommandLauncher { fShowCommand = show; } + @SuppressWarnings("deprecation") @Override public int waitAndRead(OutputStream out, OutputStream err) { + + if (usingLocalLauncher) { + return fLocalLauncher.waitAndRead(out, err); + } + + // otherwise remote process if (fShowCommand) { printCommandLine(out); } @@ -278,6 +302,11 @@ public class RemoteCommandLauncher implements ICommandLauncher { @Override public int waitAndRead(OutputStream out, OutputStream err, IProgressMonitor monitor) { + if (usingLocalLauncher) { + return fLocalLauncher.waitAndRead(out, err, monitor); + } + + // otherwise remote process if (fShowCommand) { printCommandLine(out); }