/******************************************************************************* * Copyright (c) 2005, 2011 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 *******************************************************************************/ 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; 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.core.settings.model.util.CDataUtil; 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.StorableEnvironment; import org.eclipse.cdt.utils.envvar.StorableEnvironmentLoader; 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 static final String fNonOverloadableVariables[] = new String[]{ //users not allowed currently to override the "CWD" and "PWD" variables EnvVarOperationProcessor.normalizeName("CWD"), //$NON-NLS-1$ EnvVarOperationProcessor.normalizeName("PWD") //$NON-NLS-1$ }; */ private StorableEnvironment fWorkspaceVariables; private StorableEnvironment fOverrideVariables = new StorableEnvironment(false); static class VarKey { private IEnvironmentVariable fVar; private boolean fNameOnly; private int fCode; VarKey(IEnvironmentVariable var, boolean nameOnly){ fVar = var; fNameOnly = nameOnly; } public IEnvironmentVariable getVariable(){ return fVar; } @Override public boolean equals(Object obj) { if(obj == this) return true; if(!(obj instanceof VarKey)) return false; VarKey other = (VarKey)obj; IEnvironmentVariable otherVar = other.fVar; if(fVar == otherVar) return true; if(!CDataUtil.objectsEqual(fVar.getName(), otherVar.getName())) return false; if(fNameOnly) return true; if(fVar.getOperation() != otherVar.getOperation()) return false; if(!CDataUtil.objectsEqual(fVar.getValue(), otherVar.getValue())) return false; if(!CDataUtil.objectsEqual(fVar.getDelimiter(),otherVar.getDelimiter())) return false; return true; } @Override public int hashCode() { int code = fCode; if(code == 0){ code = 47; String tmp = fVar.getName(); if(tmp != null) code += tmp.hashCode(); if(fNameOnly) return code; code += fVar.getOperation(); tmp = fVar.getValue(); if(tmp != null) code += tmp.hashCode(); tmp = fVar.getDelimiter(); if(tmp != null) code += tmp.hashCode(); fCode = code; } return code; } } public StorableEnvironment getEnvironment(Object context){ return getEnvironment(context,true); } protected StorableEnvironment getEnvironment(Object context, boolean forceLoad){ // if(context == null) // return null; 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 instanceof IWorkspace || context == null){ if(fWorkspaceVariables == null && forceLoad) fWorkspaceVariables = 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(){ public Preferences getNode(){ return getConfigurationNode(cfg.getProjectDescription()); } 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(){ public Preferences getNode(){ return prefs; } 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 = new InstanceScope().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){ StorableEnvironment oldEnv = getEnvironment(null); fWorkspaceVariables = new StorableEnvironment(env, false); EnvironmentChangeEvent event = createEnvironmentChangeEvent(fWorkspaceVariables.getVariables(), oldEnv.getVariables()); storeWorkspaceEnvironment(true); // updateProjectInfo(null); return event != null; } static EnvironmentChangeEvent createEnvironmentChangeEvent(IEnvironmentVariable[] newVars, IEnvironmentVariable[] oldVars){ IEnvironmentVariable[] addedVars = null, removedVars = null, changedVars = null; if(oldVars == null || oldVars.length == 0){ if(newVars != null && newVars.length != 0) addedVars = newVars.clone(); } else if(newVars == null || newVars.length == 0){ removedVars = oldVars.clone(); } else { HashSet<VarKey> newSet = new HashSet<VarKey>(newVars.length); HashSet<VarKey> oldSet = new HashSet<VarKey>(oldVars.length); for (IEnvironmentVariable newVar : newVars) { newSet.add(new VarKey(newVar, true)); } for (IEnvironmentVariable oldVar : oldVars) { oldSet.add(new VarKey(oldVar, true)); } @SuppressWarnings("unchecked") HashSet<VarKey> newSetCopy = (HashSet<VarKey>)newSet.clone(); newSet.removeAll(oldSet); oldSet.removeAll(newSetCopy); if(newSet.size() != 0){ addedVars = varsFromKeySet(newSet); } if(oldSet.size() != 0){ removedVars = varsFromKeySet(oldSet); } newSetCopy.removeAll(newSet); HashSet<VarKey> modifiedSet = new HashSet<VarKey>(newSetCopy.size()); for (VarKey key : newSetCopy) { modifiedSet.add(new VarKey(key.getVariable(), false)); } for (IEnvironmentVariable oldVar : oldVars) { modifiedSet.remove(new VarKey(oldVar, false)); } if(modifiedSet.size() != 0) changedVars = varsFromKeySet(modifiedSet); } if(addedVars != null || removedVars != null || changedVars != null) return new EnvironmentChangeEvent(addedVars, removedVars, changedVars); return null; } static IEnvironmentVariable[] varsFromKeySet(Set<VarKey> set){ IEnvironmentVariable vars[] = new IEnvironmentVariable[set.size()]; int i = 0; for(Iterator<VarKey> iter = set.iterator(); iter.hasNext(); i++){ VarKey key = iter.next(); vars[i] = key.getVariable(); } return vars; } 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) { } } } /* (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.envvar.IEnvironmentVariableSupplier#getVariable() */ 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); } /* (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.envvar.IEnvironmentVariableSupplier#getVariables() */ 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()){ // updateProjectInfo(context); 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); if(var != null){ // updateProjectInfo(context); } return var; } public void deleteAll(Object context){ StorableEnvironment env = getEnvironment(context); if(env == null) return; if(env.deleteAll()){ // updateProjectInfo(context); } } public void setVariables(IEnvironmentVariable vars[], Object context){ StorableEnvironment env = getEnvironment(context); if(env == null) return; env.setVariales(vars); if(env.isChanged()){ // updateProjectInfo(context); env.setChanged(false); } } // protected void updateProjectInfo(Object context){ // } // protected void cfgVarsModified(ICConfigurationDescription cfg){ // cfg.setRebuildState(true); // EnvironmentVariableProvider.getDefault().checkBuildPathVariables(cfg); // } protected String getValidName(String name){ if(name == null || (name = name.trim()).length() == 0) return null; // if(fNonOverloadableVariables != null){ // for(int i = 0; i < fNonOverloadableVariables.length; i++){ // if(fNonOverloadableVariables[i].equals(EnvVarOperationProcessor.normalizeName(name))) // return null; // } // } return name; } protected IEnvironmentVariable[] filterVariables(IEnvironmentVariable variables[]){ return EnvVarOperationProcessor.filterVariables(variables,null); } 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(); } } }