/******************************************************************************* * Copyright (c) 2005, 2013 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 * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Intel Corporation - Initial API and implementation * James Blackburn (Broadcom Corp.) * IBM Corporation * Andrew Gvozdev - Notification mechanism for changes to environment variables *******************************************************************************/ package org.eclipse.cdt.internal.core.envvar; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.envvar.IEnvironmentVariable; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.internal.core.settings.model.CConfigurationSpecSettings; import org.eclipse.cdt.internal.core.settings.model.IInternalCCfgInfo; import org.eclipse.cdt.utils.envvar.EnvVarOperationProcessor; import org.eclipse.cdt.utils.envvar.IEnvironmentChangeListener; import org.eclipse.cdt.utils.envvar.PrefsStorableEnvironment; import org.eclipse.cdt.utils.envvar.StorableEnvironment; import org.eclipse.cdt.utils.envvar.StorableEnvironmentLoader; import org.eclipse.core.resources.IBuildConfiguration; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.ProjectScope; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.preferences.InstanceScope; import org.osgi.service.prefs.BackingStoreException; import org.osgi.service.prefs.Preferences; /** * 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. * * <p> * This class is Singleton held by {@link EnvironmentVariableManager}. * * <p> * 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 StorableEnvironmentLoader implements ICoreEnvironmentVariableSupplier { public static final String NODENAME = "environment"; //$NON-NLS-1$ public static final String PREFNAME_WORKSPACE = "workspace"; //$NON-NLS-1$ public static final String PREFNAME_PROJECT = "project"; //$NON-NLS-1$ public static final String NODENAME_CFG = "project"; //$NON-NLS-1$ private PrefsStorableEnvironment fWorkspaceVariables; private StorableEnvironment fOverrideVariables = new StorableEnvironment(false); public StorableEnvironment getEnvironment(Object context) { return getEnvironment(context, false); } protected StorableEnvironment getEnvironment(Object context, boolean forceLoad) { StorableEnvironment env = null; if (context instanceof IInternalCCfgInfo) { try { CConfigurationSpecSettings settings = ((IInternalCCfgInfo)context).getSpecSettings(); env = settings.getEnvironment(); if (env == null || forceLoad) { env = loadEnvironment(context, settings.isReadOnly()); settings.setEnvironment(env); } } catch (CoreException e) { CCorePlugin.log(e); } } else if (context == null || context instanceof IBuildConfiguration || context instanceof IWorkspace) { if (fWorkspaceVariables == null || forceLoad) fWorkspaceVariables = (PrefsStorableEnvironment) loadEnvironment(context, false); env = fWorkspaceVariables; } return env; } @Override protected ISerializeInfo getSerializeInfo(Object context) { ISerializeInfo serializeInfo = null; if (context instanceof ICConfigurationDescription) { final ICConfigurationDescription cfg = (ICConfigurationDescription)context; final String name = cfg.getId(); if (name != null) serializeInfo = new ISerializeInfo() { @Override public Preferences getNode() { return getConfigurationNode(cfg.getProjectDescription()); } @Override public String getPrefName() { return name; } }; } else if (context == null || context instanceof IWorkspace) { final Preferences prefs = getWorkspaceNode(); final String name = PREFNAME_WORKSPACE; if (prefs != null) serializeInfo = new ISerializeInfo() { @Override public Preferences getNode() { return prefs; } @Override public String getPrefName() { return name; } }; } return serializeInfo; } private Preferences getConfigurationNode(ICProjectDescription projDes) { Preferences prefNode = getProjectNode(projDes); if (prefNode == null) return null; return prefNode.node(NODENAME_CFG); } private Preferences getProjectNode(ICProjectDescription projDes) { if (projDes == null) return null; IProject project = projDes.getProject(); if (!project.exists()) return null; Preferences prefNode = new ProjectScope(project).getNode(CCorePlugin.PLUGIN_ID); if (prefNode == null) return null; return prefNode.node(NODENAME); } private Preferences getWorkspaceNode() { Preferences prefNode = InstanceScope.INSTANCE.getNode(CCorePlugin.PLUGIN_ID); if (prefNode == null) return null; return prefNode.node(NODENAME); } public void checkInexistentConfigurations(ICProjectDescription projDes) { Preferences prefNode = getConfigurationNode(projDes); if (prefNode == null) return; try{ String ids[] = prefNode.keys(); boolean found = false; for (String id : ids) { if (projDes.getConfigurationById(id) == null) { prefNode.remove(id); found = true; } } if (found) prefNode.flush(); } catch(BackingStoreException e) { } } public void storeWorkspaceEnvironment(boolean force) { if (fWorkspaceVariables != null) { try{ storeEnvironment(fWorkspaceVariables,ResourcesPlugin.getWorkspace(),force, true); } catch(CoreException e) { } } } public StorableEnvironment getWorkspaceEnvironmentCopy() { StorableEnvironment envVar = getEnvironment(null); return new StorableEnvironment(envVar, false); } public boolean setWorkspaceEnvironment(StorableEnvironment env) { IEnvironmentVariable[] oldVariables = fWorkspaceVariables.getVariables(); IEnvironmentVariable[] newVariables = env.getVariables(); fWorkspaceVariables.deleteAll(); fWorkspaceVariables.setVariales(newVariables); fWorkspaceVariables.setAppendEnvironment(env.appendEnvironment()); fWorkspaceVariables.setAppendContributedEnvironment(env.appendContributedEnvironment()); storeWorkspaceEnvironment(true); return ! Arrays.equals(oldVariables, newVariables); } public void storeProjectEnvironment(ICProjectDescription des, boolean force) { ICConfigurationDescription cfgs[] = des.getConfigurations(); for (ICConfigurationDescription cfg : cfgs) { storeEnvironment(cfg, force, false); } Preferences node = getProjectNode(des); try { node.flush(); } catch (BackingStoreException e) { } } private void storeEnvironment(Object context, boolean force, boolean flush) { StorableEnvironment env = getEnvironment(context, false); if (env != null) { try { storeEnvironment(env, context, force, flush); } catch (CoreException e) { } } } @Override 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 var; return EnvVarOperationProcessor.performOperation(env.getVariable(name), var); } @Override public IEnvironmentVariable[] getVariables(Object context) { StorableEnvironment env = getEnvironment(context); if (env == null) return null; IEnvironmentVariable[] override = filterVariables(fOverrideVariables.getVariables()); IEnvironmentVariable[] normal = filterVariables(env.getVariables()); return combineVariables(normal, override); } private IEnvironmentVariable[] combineVariables(IEnvironmentVariable[] oldVariables, IEnvironmentVariable[] newVariables) { Map<String, IEnvironmentVariable> vars = new HashMap<String, IEnvironmentVariable>(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; StorableEnvironment env = getEnvironment(context); if (env == null) return null; IEnvironmentVariable var = env.createVariable(name,value,op,delimiter); if (env.isChanged()) { env.setChanged(false); } return var; } public IEnvironmentVariable deleteVariable(String name, Object context) { StorableEnvironment env = getEnvironment(context); if (env == null) return null; IEnvironmentVariable var = env.deleteVariable(name); return var; } public void deleteAll(Object context) { StorableEnvironment env = getEnvironment(context); if (env == null) return; env.deleteAll(); } public void setVariables(IEnvironmentVariable vars[], Object context) { StorableEnvironment env = getEnvironment(context); if (env == null) return; env.setVariales(vars); if (env.isChanged()) { env.setChanged(false); } } protected String getValidName(String name) { if (name == null || (name = name.trim()).length() == 0) return null; return name; } protected IEnvironmentVariable[] filterVariables(IEnvironmentVariable variables[]) { return EnvVarOperationProcessor.filterVariables(variables,null); } @Override public boolean appendEnvironment(Object context) { StorableEnvironment env = getEnvironment(context); if (env == null) return true; return env.appendEnvironment(); } public boolean appendContributedEnvironment(Object context) { StorableEnvironment env = getEnvironment(context); if (env == null) return true; return env.appendContributedEnvironment(); } public void setAppendEnvironment(boolean append, Object context) { StorableEnvironment env = getEnvironment(context); if (env != null) { env.setAppendEnvironment(append); } } public void setAppendContributedEnvironment(boolean append, Object context) { StorableEnvironment env = getEnvironment(context); if (env != null) { env.setAppendContributedEnvironment(append); } } public void restoreDefaults(Object context) { StorableEnvironment env = getEnvironment(context); if (env != null) { env.restoreDefaults(); } } /** * Adds a listener that will be notified of changes in environment variables. * * @param listener - the listener to add * @since 5.5 */ public void registerEnvironmentChangeListener(IEnvironmentChangeListener listener) { if (fWorkspaceVariables == null) { getEnvironment(null, false); } if (fWorkspaceVariables != null) { fWorkspaceVariables.registerEnvironmentChangeListener(listener); } } /** * Removes an environment variables change listener. * * @param listener - the listener to remove. * @since 5.5 */ public void unregisterEnvironmentChangeListener(IEnvironmentChangeListener listener) { if (fWorkspaceVariables != null) { fWorkspaceVariables.unregisterEnvironmentChangeListener(listener); } } }