From bf5233d4e48cf48c4a0217da905c0fca9b1dae75 Mon Sep 17 00:00:00 2001 From: James Blackburn Date: Mon, 23 Aug 2010 14:43:15 +0000 Subject: [PATCH] Bug 321588 - Headless Builder allow extending the build environment from the command line --- .../internal/core/HeadlessBuildMessages.java | 4 ++ .../core/HeadlessBuildMessages.properties | 6 +- .../internal/core/HeadlessBuilder.java | 30 +++++++++ .../org.eclipse.cdt.core/META-INF/MANIFEST.MF | 2 +- .../UserDefinedEnvironmentSupplier.java | 66 +++++++++++++++---- 5 files changed, 95 insertions(+), 13 deletions(-) diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/HeadlessBuildMessages.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/HeadlessBuildMessages.java index 71ed24e1fde..62d33f9e422 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/HeadlessBuildMessages.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/HeadlessBuildMessages.java @@ -22,6 +22,10 @@ public class HeadlessBuildMessages extends NLS { public static String HeadlessBuilder_cleaning_all_projects; public static String HeadlessBuilder_CouldntLockWorkspace; public static String HeadlessBuilder_Directory; + public static String HeadlessBuilder_EnvVar_Append; + public static String HeadlessBuilder_EnvVar_Prepend; + public static String HeadlessBuilder_EnvVar_Remove; + public static String HeadlessBuilder_EnvVar_Replace; public static String HeadlessBuilder_Error; public static String HeadlessBuilder_importAll; public static String HeadlessBuilder_IncludeFile; diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/HeadlessBuildMessages.properties b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/HeadlessBuildMessages.properties index 84efdc6c0c0..42bd31c75dc 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/HeadlessBuildMessages.properties +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/HeadlessBuildMessages.properties @@ -17,6 +17,10 @@ HeadlessBuilder_clean_failed=Couldn't CLEAN project HeadlessBuilder_cleaning_all_projects=Cleaning All Projects... HeadlessBuilder_CouldntLockWorkspace=Could not obtain lock for workspace location HeadlessBuilder_Directory=Directory: +HeadlessBuilder_EnvVar_Append=\ \ \ -Ea {var=value} append value to environment variable when running all tools +HeadlessBuilder_EnvVar_Prepend=\ \ \ -Ep {var=value} prepend value to environment variable when running all tools +HeadlessBuilder_EnvVar_Remove=\ \ \ -Er {var} remove/unset the given environment variable +HeadlessBuilder_EnvVar_Replace=\ \ \ -E {var=value} replace/add value to environment variable when running all tools HeadlessBuilder_Error=Error: HeadlessBuilder_invalid_argument=Invalid Arguments: HeadlessBuilder_is_not_accessible=\ is not accessible\! @@ -36,7 +40,7 @@ HeadlessBuilder_usage=Usage: HeadlessBuilder_usage_build=\ \ \ -build {project_name_reg_ex{/config_reg_ex} | all} HeadlessBuilder_usage_clean_build=\ \ \ -cleanBuild {project_name_reg_ex{/config_reg_ex} | all} HeadlessBuilder_usage_import=\ \ \ -import {[uri:/]/path/to/project} -HeadlessBuilder_importAll=\ \ \ -importAll {[uri:/]/path/to/projectTreeURI} Import all projects under URI +HeadlessBuilder_importAll=\ \ \ -importAll {[uri:/]/path/to/projectTreeURI} Import all projects under URI HeadlessBuilder_IncludeFile=\ \ \ -include {include_file} additional include_file to pass to tools HeadlessBuilder_InlucdePath=\ \ \ -I {include_path} additional include_path to add to tools HeadlessBuilder_invalid_uri=Invalid project URI: diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/HeadlessBuilder.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/HeadlessBuilder.java index c9c1519e092..dbc730939b1 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/HeadlessBuilder.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/HeadlessBuilder.java @@ -28,6 +28,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; +import org.eclipse.cdt.core.envvar.IEnvironmentVariable; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.resources.ACBuilder; import org.eclipse.cdt.core.settings.model.CIncludeFileEntry; @@ -35,6 +36,7 @@ import org.eclipse.cdt.core.settings.model.CIncludePathEntry; import org.eclipse.cdt.core.settings.model.CMacroEntry; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescription; +import org.eclipse.cdt.internal.core.envvar.EnvironmentVariableManager; import org.eclipse.cdt.managedbuilder.core.IConfiguration; import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin; @@ -76,6 +78,10 @@ import org.eclipse.osgi.service.datalocation.Location; * - Add Include path to build : -I {include_path} * - Add Include file to build : -include {include_file} * - Add preprocessor define to build : -D {prepoc_define} + * - Replace environment variable in build : -E {var=value} + * - Append environment variable to build : -Ea {var=value} + * - Prepend environment variable to build : -Ep {var=value} + * - Remove environment variable in build : -Er {var} * * Build output is automatically sent to stdout. * @since 6.0 @@ -480,6 +486,10 @@ public class HeadlessBuilder implements IApplication { * -I {include_path} additional include_path to add to tools * -include {include_file} additional include_file to pass to tools * -D {prepoc_define} addition preprocessor defines to pass to the tools + * -E {var=value} replace/add value to environment variable when running all tools + * -Ea {var=value} append value to environment variable when running all tools + * -Ep {var=value} prepend value to environment variable when running all tools + * -Er {var} remove/unset the given environment variable * * Each argument may be specified more than once * @param args String[] of arguments to parse @@ -510,6 +520,14 @@ public class HeadlessBuilder implements IApplication { HeadlessBuilderExternalSettingsProvider.additionalSettings.add(new CIncludePathEntry(args[++i], 0)); } else if ("-include".equals(args[i])) { //$NON-NLS-1$ HeadlessBuilderExternalSettingsProvider.additionalSettings.add(new CIncludeFileEntry(args[++i], 0)); + } else if ("-E".equals(args[i])) { //$NON-NLS-1$ + addEnvironmentVariable(args[++i], IEnvironmentVariable.ENVVAR_REPLACE); + } else if ("-Ea".equals(args[i])) { //$NON-NLS-1$ + addEnvironmentVariable(args[++i], IEnvironmentVariable.ENVVAR_APPEND); + } else if ("-Ep".equals(args[i])) { //$NON-NLS-1$ + addEnvironmentVariable(args[++i], IEnvironmentVariable.ENVVAR_PREPEND); + } else if ("-Er".equals(args[i])) { //$NON-NLS-1$ + addEnvironmentVariable(args[++i], IEnvironmentVariable.ENVVAR_REMOVE); } else { throw new Exception(HeadlessBuildMessages.HeadlessBuilder_unknown_argument + args[i]); } @@ -526,6 +544,10 @@ public class HeadlessBuilder implements IApplication { System.err.println(HeadlessBuildMessages.HeadlessBuilder_InlucdePath); System.err.println(HeadlessBuildMessages.HeadlessBuilder_IncludeFile); System.err.println(HeadlessBuildMessages.HeadlessBuilder_PreprocessorDefine); + System.err.println(HeadlessBuildMessages.HeadlessBuilder_EnvVar_Replace); + System.err.println(HeadlessBuildMessages.HeadlessBuilder_EnvVar_Append); + System.err.println(HeadlessBuildMessages.HeadlessBuilder_EnvVar_Prepend); + System.err.println(HeadlessBuildMessages.HeadlessBuilder_EnvVar_Remove); return false; } @@ -544,6 +566,14 @@ public class HeadlessBuilder implements IApplication { return true; } + private void addEnvironmentVariable(String string, int op) throws Exception { + String[] parts = string.split("=", 2); //$NON-NLS-1$ + String name = parts[0]; + String value = ""; //$NON-NLS-1$ + if (parts.length > 1) + value = parts[1]; + EnvironmentVariableManager.fUserSupplier.createOverrideVariable(name, value, op, null); + } public void stop() { } diff --git a/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF b/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF index c20d23180e4..3246d75a024 100644 --- a/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF +++ b/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF @@ -53,7 +53,7 @@ Export-Package: org.eclipse.cdt.core, org.eclipse.cdt.internal.core.dom.rewrite.changegenerator;x-internal:=true, org.eclipse.cdt.internal.core.dom.rewrite.commenthandler;x-internal:=true, org.eclipse.cdt.internal.core.dom.rewrite.util;x-internal:=true, - org.eclipse.cdt.internal.core.envvar;x-friends:="org.eclipse.cdt.ui", + org.eclipse.cdt.internal.core.envvar;x-friends:="org.eclipse.cdt.ui,org.eclipse.cdt.managedbuilder.core", org.eclipse.cdt.internal.core.index;x-friends:="org.eclipse.cdt.ui", org.eclipse.cdt.internal.core.index.composite;x-internal:=true, org.eclipse.cdt.internal.core.index.composite.c;x-internal:=true, diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/envvar/UserDefinedEnvironmentSupplier.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/envvar/UserDefinedEnvironmentSupplier.java index eba744bb03e..706f6530bed 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/envvar/UserDefinedEnvironmentSupplier.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/envvar/UserDefinedEnvironmentSupplier.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2009 Intel Corporation and others. + * Copyright (c) 2005, 2010 Intel Corporation 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 @@ -11,8 +11,10 @@ *******************************************************************************/ package org.eclipse.cdt.internal.core.envvar; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.Map; import java.util.Set; import org.eclipse.cdt.core.CCorePlugin; @@ -35,9 +37,18 @@ import org.osgi.service.prefs.BackingStoreException; import org.osgi.service.prefs.Preferences; /** - * This is the Environment Variable Supplier used to supply variables - * defined by a user - * + * This is the Environment Variable Supplier used to supply and persist user + * defined variables. Variables are stored in the context of a CDT {@link ICConfigurationDescription}, + * or, globally at the {@link IWorkspace} level. + * + *

+ * This class is Singleton held by {@link EnvironmentVariableManager}. + * + *

+ * It also allows temporary 'overriding' of variables. These are not persisted, but override + * the values of any existing user-defined variable. This functionality is used by HeadlessBuilder + * to temporarily override environment variables on the command line. + * * @since 3.0 */ public class UserDefinedEnvironmentSupplier extends @@ -56,8 +67,8 @@ public class UserDefinedEnvironmentSupplier extends }; */ private StorableEnvironment fWorkspaceVariables; - - + private StorableEnvironment fOverrideVariables = new StorableEnvironment(false); + static class VarKey { private IEnvironmentVariable fVar; private boolean fNameOnly; @@ -375,10 +386,11 @@ public class UserDefinedEnvironmentSupplier extends public IEnvironmentVariable getVariable(String name, Object context) { if(getValidName(name) == null) return null; + IEnvironmentVariable var = fOverrideVariables.getVariable(name); StorableEnvironment env = getEnvironment(context); - if(env == null) - return null; - return env.getVariable(name); + if (env == null) + return var; + return EnvVarOperationProcessor.performOperation(env.getVariable(name), var); } /* (non-Javadoc) @@ -388,9 +400,41 @@ public class UserDefinedEnvironmentSupplier extends StorableEnvironment env = getEnvironment(context); if(env == null) return null; - return filterVariables(env.getVariables()); + IEnvironmentVariable[] override = filterVariables(fOverrideVariables.getVariables()); + IEnvironmentVariable[] normal = filterVariables(env.getVariables()); + return combineVariables(normal, override); } - + + private IEnvironmentVariable[] combineVariables(IEnvironmentVariable[] oldVariables, IEnvironmentVariable[] newVariables) { + Map vars = new HashMap(oldVariables.length + newVariables.length); + for (IEnvironmentVariable variable : oldVariables) + vars.put(variable.getName(), variable); + for (IEnvironmentVariable variable : newVariables) { + if (!vars.containsKey(variable.getName())) + vars.put(variable.getName(), variable); + else + vars.put(variable.getName(), EnvVarOperationProcessor.performOperation(vars.get(variable.getName()), variable)); + } + return vars.values().toArray(new IEnvironmentVariable[vars.size()]); + } + + /** + * Add an environment variable 'override'. This variable won't be persisted but will instead + * replace / remove / prepend / append any existing environment variable with the same name. + * This change is not persisted and remains for the current eclipse session. + * + * @param name Environment variable name + * @param value Environment variable value + * @param op one of the IBuildEnvironmentVariable.ENVVAR_* operation types + * @param delimiter delimiter to use or null for default + * @return Overriding IEnvironmentVariable or null if name is not valid + */ + public IEnvironmentVariable createOverrideVariable(String name, String value, int op, String delimiter) { + if (getValidName(name) == null) + return null; + return fOverrideVariables.createVariable(name,value,op,delimiter); + } + public IEnvironmentVariable createVariable(String name, String value, int op, String delimiter, Object context){ if(getValidName(name) == null) return null;