/*******************************************************************************
* Copyright (c) 2007, 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
*******************************************************************************/
package org.eclipse.cdt.managedbuilder.internal.tcmodification;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import org.eclipse.cdt.managedbuilder.core.IConfiguration;
import org.eclipse.cdt.managedbuilder.core.IFolderInfo;
import org.eclipse.cdt.managedbuilder.core.IManagedProject;
import org.eclipse.cdt.managedbuilder.core.IResourceInfo;
import org.eclipse.cdt.managedbuilder.core.ITool;
import org.eclipse.cdt.managedbuilder.core.IToolChain;
import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager;
import org.eclipse.cdt.managedbuilder.internal.core.FolderInfo;
import org.eclipse.cdt.managedbuilder.internal.core.IRealBuildObjectAssociation;
import org.eclipse.cdt.managedbuilder.internal.core.ResourceInfo;
import org.eclipse.cdt.managedbuilder.internal.core.Tool;
import org.eclipse.cdt.managedbuilder.internal.core.ToolChain;
import org.eclipse.cdt.managedbuilder.internal.dataprovider.ConfigurationDataProvider;
import org.eclipse.cdt.managedbuilder.internal.tcmodification.ToolChainModificationManager.ConflictMatch;
import org.eclipse.cdt.managedbuilder.internal.tcmodification.ToolChainModificationManager.ConflictMatchSet;
import org.eclipse.cdt.managedbuilder.tcmodification.CompatibilityStatus;
import org.eclipse.cdt.managedbuilder.tcmodification.IFolderInfoModification;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
public class FolderInfoModification extends ToolListModification implements IFolderInfoModification {
private ToolChain fRealToolChain;
private ToolChainCompatibilityInfoElement fCurrentCompatibilityInfo;
private ToolChain fSelectedToolChain;
private IToolChain[] fAllSysToolChains;
private Map<ToolChain, ToolChainCompatibilityInfoElement> fCompatibleToolChains;
private Map<ToolChain, ToolChainCompatibilityInfoElement> fInCompatibleToolChains;
private PerTypeMapStorage<IRealBuildObjectAssociation, Set<IPath>> fParentObjectStorage;
private ConflictMatchSet fParentConflicts;
// private PerTypeMapStorage fChildObjectStorage;
// private ConflictMatchSet fChildConflicts;
private boolean fCompatibilityInfoInited;
private ToolChainApplicabilityPaths fTcApplicabilityPaths;
public FolderInfoModification(FolderInfo foInfo) {
super(foInfo, foInfo.getTools());
fSelectedToolChain = (ToolChain)foInfo.getToolChain();
fRealToolChain = (ToolChain)ManagedBuildManager.getRealToolChain(fSelectedToolChain);
}
public FolderInfoModification(FolderInfo foInfo, FolderInfoModification base) {
super(foInfo, base);
fSelectedToolChain = base.fSelectedToolChain;
if(!fSelectedToolChain.isExtensionElement())
fSelectedToolChain = (ToolChain)fSelectedToolChain.getExtensionObject();
fRealToolChain = base.fRealToolChain;
}
private ConflictMatchSet getParentConflictMatchSet(){
if(fParentConflicts == null){
PerTypeMapStorage<IRealBuildObjectAssociation, Set<IPath>> storage = getParentObjectStorage();
fParentConflicts = ToolChainModificationManager.getInstance().getConflictInfo(IRealBuildObjectAssociation.OBJECT_TOOLCHAIN, storage);
}
return fParentConflicts;
}
private PerTypeMapStorage<IRealBuildObjectAssociation, Set<IPath>> getParentObjectStorage(){
if(fParentObjectStorage == null){
fParentObjectStorage = TcModificationUtil.createParentObjectsRealToolToPathSet((FolderInfo)getResourceInfo());
}
return fParentObjectStorage;
}
private IToolChain[] getAllSysToolChains(){
if(fAllSysToolChains == null)
fAllSysToolChains = ManagedBuildManager.getRealToolChains();
return fAllSysToolChains;
}
private static class ToolChainApplicabilityPaths {
private Set<IPath> fFileInfoPaths = new HashSet<IPath>();
private Set<IPath> fFolderInfoPaths = new HashSet<IPath>();
private Map<Tool, Set<IPath>> fToolPathMap = new HashMap<Tool, Set<IPath>>();
}
public static class ToolChainCompatibilityInfoElement {
private ToolChain fTc;
private List<ConflictMatch> fErrComflictMatchList;
// private List fWarningConflictMatchList;
private CompatibilityStatus fStatus;
ToolChainCompatibilityInfoElement(ToolChain tc, List<ConflictMatch> errConflictList){
fTc = tc;
if(errConflictList != null && errConflictList.size() != 0)
fErrComflictMatchList = errConflictList;
}
public CompatibilityStatus getCompatibilityStatus(){
if(fStatus == null){
int severity;
String message;
if(fErrComflictMatchList != null){
severity = IStatus.ERROR;
message = Messages.getString("FolderInfoModification.0"); //$NON-NLS-1$
} else {
severity = IStatus.OK;
message = ""; //$NON-NLS-1$
}
fStatus = new CompatibilityStatus(severity, message, new ConflictSet(fTc, fErrComflictMatchList, null));
}
return fStatus;
}
public boolean isCompatible(){
return fErrComflictMatchList == null;
}
}
@Override
public IToolChain[] getCompatibleToolChains(){
initCompatibilityInfo();
FolderInfo foInfo = (FolderInfo)getResourceInfo();
List<ToolChain> l = new ArrayList<ToolChain>(fCompatibleToolChains.size());
Set<ToolChain> keySet = fCompatibleToolChains.keySet();
for (ToolChain tc : keySet) {
if(tc != fRealToolChain && foInfo.isToolChainCompatible(fRealToolChain, tc))
l.add(tc);
}
return l.toArray(new ToolChain[l.size()]);
}
@Override
public CompatibilityStatus getToolChainCompatibilityStatus(){
return getCurrentCompatibilityInfo().getCompatibilityStatus();
}
private ToolChainCompatibilityInfoElement getCurrentCompatibilityInfo(){
if(fCurrentCompatibilityInfo == null){
initCompatibilityInfo();
ToolChainCompatibilityInfoElement info = fCompatibleToolChains.get(fRealToolChain);
if(info == null)
info = fInCompatibleToolChains.get(fRealToolChain);
fCurrentCompatibilityInfo = info;
}
return fCurrentCompatibilityInfo;
}
@Override
public boolean isToolChainCompatible(){
return getCurrentCompatibilityInfo().isCompatible();
}
private void initCompatibilityInfo(){
if(fCompatibilityInfoInited)
return;
fCompatibleToolChains = new HashMap<ToolChain, ToolChainCompatibilityInfoElement>();
fInCompatibleToolChains = new HashMap<ToolChain, ToolChainCompatibilityInfoElement>();
ConflictMatchSet parentConflicts = getParentConflictMatchSet();
ToolChain sysTCs[] = (ToolChain[])getAllSysToolChains();
@SuppressWarnings("unchecked")
Map<ToolChain, List<ConflictMatch>> conflictMap = (Map<ToolChain, List<ConflictMatch>>) parentConflicts.fObjToConflictListMap;
for (ToolChain tc : sysTCs) {
List<ConflictMatch> l = conflictMap.get(tc);
ToolChainCompatibilityInfoElement info = new ToolChainCompatibilityInfoElement(tc, l);
if(info.isCompatible()){
fCompatibleToolChains.put(tc, info);
} else {
fInCompatibleToolChains.put(tc, info);
}
}
fCompatibilityInfoInited = true;
}
@Override
public IToolChain getToolChain(){
return fSelectedToolChain;
}
@Override
public final void setToolChain(IToolChain tc){
setToolChain(tc, false);
}
public void setToolChain(IToolChain tc, boolean force){
if(tc == fSelectedToolChain && !force)
return;
applyToolChain((ToolChain)tc);
fSelectedToolChain = (ToolChain)tc;
IToolChain newReal = ManagedBuildManager.getRealToolChain(tc);
if(newReal == fRealToolChain && !force)
return;
fRealToolChain = (ToolChain)newReal;
// setProjectTools(tc.getTools());
// applyToolChain(fSelectedToolChain);
clearToolInfo(tc.getTools());
fCurrentCompatibilityInfo = null;
}
protected void clearToolChainCompatibilityInfo(){
fCompatibilityInfoInited = false;
fCompatibleToolChains = null;
fInCompatibleToolChains = null;
fCurrentCompatibilityInfo = null;
}
@Override
protected boolean canRemove(ITool realTool) {
IToolChain extTc = ManagedBuildManager.getExtensionToolChain(fSelectedToolChain);
ITool[] tools = extTc.getTools();
for(int i = 0; i < tools.length; i++){
if(realTool == ManagedBuildManager.getRealTool(tools[i]))
return false;
}
return true;
}
@Override
protected boolean canAdd(Tool tool) {
return !TcModificationUtil.containCommonEntries(getInputExtsSet(), tool.getPrimaryInputExtensions());
}
@Override
protected boolean canReplace(Tool fromTool, Tool toTool) {
String[] exts = toTool.getPrimaryInputExtensions();
Set<String> curInputExts = null;
Set<String> inputExts = getInputExtsSet();
for (String ext : exts) {
if(inputExts.contains(ext)){
if(curInputExts == null)
curInputExts = new HashSet<String>(Arrays.asList(fromTool.getPrimaryInputExtensions()));
if(curInputExts.contains(ext)){
return true;
}
}
}
return false;
}
@Override
protected Set<Tool> getExtensionConflictToolSet(Tool tool, Tool[] tools) {
String exts[] = tool.getPrimaryInputExtensions();
Set<String> extsSet = new HashSet<String>(Arrays.asList(exts));
Set<Tool> conflictsSet = null;
for(int i = 0; i < tools.length; i++){
Tool t = tools[i];
if(t == tool)
continue;
if(TcModificationUtil.containCommonEntries(extsSet, t.getPrimaryInputExtensions())){
if(conflictsSet == null)
conflictsSet = new HashSet<Tool>();
conflictsSet.add(t);
}
}
if(conflictsSet == null)
conflictsSet = Collections.emptySet();
return conflictsSet;
}
@Override
protected Set<IPath> getToolApplicabilityPathSet(Tool realTool, boolean isProject) {
if(isProject)
return getToolChainApplicabilityPaths().fToolPathMap.get(realTool);
return getToolChainApplicabilityPaths().fFolderInfoPaths;
}
@Override
protected Tool[] filterTools(Tool[] tools) {
IResourceInfo rcInfo = getResourceInfo();
return (Tool[])((FolderInfo)rcInfo).filterTools(tools, rcInfo.getParent().getManagedProject());
}
private ToolChainApplicabilityPaths getToolChainApplicabilityPaths(){
initToolChainApplicabilityPaths();
return fTcApplicabilityPaths;
}
private void initToolChainApplicabilityPaths(){
if(fTcApplicabilityPaths != null)
return;
ToolChainApplicabilityPaths tcApplicabilityPaths = new ToolChainApplicabilityPaths();
IPath path = getResourceInfo().getPath();
TreeMap<IPath, PerTypeSetStorage<IRealBuildObjectAssociation>> pathMap = getCompletePathMapStorage();
PerTypeSetStorage<? extends IRealBuildObjectAssociation> oSet = pathMap.get(path);
@SuppressWarnings("unchecked")
Set<Tool> toolSet = (Set<Tool>) oSet.getSet(IRealBuildObjectAssociation.OBJECT_TOOL, false);
@SuppressWarnings("unchecked")
Set<ToolChain> tcSet = (Set<ToolChain>) oSet.getSet(IRealBuildObjectAssociation.OBJECT_TOOLCHAIN, false);
ToolChain curTc = tcSet.iterator().next();
Set<IPath> foInfoPaths = tcApplicabilityPaths.fFolderInfoPaths;
Set<IPath> fileInfoPaths = tcApplicabilityPaths.fFileInfoPaths;
foInfoPaths.add(path);
Map<Tool, Set<IPath>> toolPathsMap = tcApplicabilityPaths.fToolPathMap;
if(toolSet != null){
for (IRealBuildObjectAssociation oa : toolSet) {
Tool tool = (Tool) oa;
Set<IPath> set = new HashSet<IPath>();
toolPathsMap.put(tool, set);
set.add(path);
}
}
calculateChildPaths(pathMap, path, curTc, foInfoPaths, toolPathsMap, fileInfoPaths);
fTcApplicabilityPaths = tcApplicabilityPaths;
}
@Override
protected void clearToolInfo(ITool[] tools){
super.clearToolInfo(tools);
fTcApplicabilityPaths = null;
}
private static void putToolInfo(Set<Tool> ct, Map<Tool, Set<IPath>> toolPathsMap, Set<IPath> fileInfoPaths, IPath p){
if(ct != null && ct.size() != 0){
for (Tool t : ct) {
Set<IPath> set = toolPathsMap.get(t);
if(set != null){
if(fileInfoPaths != null)
fileInfoPaths.add(p);
set.add(p);
}
}
}
}
private static void calculateChildPaths(TreeMap<IPath, PerTypeSetStorage<IRealBuildObjectAssociation>> pathMap, IPath path, ToolChain tc, Set<IPath> tcPaths, Map<Tool,Set<IPath>> toolPathsMap, Set<IPath> fileInfoPaths){
SortedMap<IPath, PerTypeSetStorage<IRealBuildObjectAssociation>> directCMap = PathComparator.getDirectChildPathMap(pathMap, path);
Set<Entry<IPath, PerTypeSetStorage<IRealBuildObjectAssociation>>> entrySet = directCMap.entrySet();
for (Entry<IPath, PerTypeSetStorage<IRealBuildObjectAssociation>> entry : entrySet) {
PerTypeSetStorage<? extends IRealBuildObjectAssociation> cst = entry.getValue();
@SuppressWarnings("unchecked")
Set<ToolChain> ctc = (Set<ToolChain>) cst.getSet(IRealBuildObjectAssociation.OBJECT_TOOLCHAIN, false);
@SuppressWarnings("unchecked")
Set<Tool> ct = (Set<Tool>) cst.getSet(IRealBuildObjectAssociation.OBJECT_TOOL, false);
if(ctc == null || ctc.size() == 0){
//fileInfo, check for tools
putToolInfo(ct, toolPathsMap, fileInfoPaths, entry.getKey());
} else {
if(ctc.contains(tc)){
IPath cp = entry.getKey();
tcPaths.add(cp);
putToolInfo(ct, toolPathsMap, null, entry.getKey());
//recurse
calculateChildPaths(pathMap, cp, tc, tcPaths, toolPathsMap, fileInfoPaths);
}
}
}
}
private void applyToolChain(ToolChain newNonRealTc){
ToolChain newRealTc = (ToolChain)ManagedBuildManager.getRealToolChain(newNonRealTc);
ToolChainApplicabilityPaths tcApplicability = getToolChainApplicabilityPaths();
PerTypeMapStorage<? extends IRealBuildObjectAssociation, Set<IPath>> storage = getCompleteObjectStore();
@SuppressWarnings("unchecked")
Map<ToolChain, Set<IPath>> tcMap = (Map<ToolChain, Set<IPath>>) storage.getMap(IRealBuildObjectAssociation.OBJECT_TOOLCHAIN, false);
@SuppressWarnings("unchecked")
Map<Tool, Set<IPath>> toolMap = (Map<Tool, Set<IPath>>) storage.getMap(IRealBuildObjectAssociation.OBJECT_TOOL, false);
TcModificationUtil.removePaths(tcMap, fRealToolChain, tcApplicability.fFolderInfoPaths);
TcModificationUtil.addPaths(tcMap, newRealTc, tcApplicability.fFolderInfoPaths);
Tool[] newTools = (Tool[])newNonRealTc.getTools();
for(int i = 0; i < newTools.length; i++){
newTools[i] = (Tool)ManagedBuildManager.getRealTool(newTools[i]);
}
Set<Entry<Tool, Set<IPath>>> entrySet = tcApplicability.fToolPathMap.entrySet();
for(Iterator<Entry<Tool, Set<IPath>>> iter = entrySet.iterator(); iter.hasNext(); ){
Map.Entry<Tool, Set<IPath>> entry = iter.next();
Tool tool = entry.getKey();
Set<IPath> pathSet = entry.getValue();
TcModificationUtil.removePaths(toolMap, tool, pathSet);
}
for(int i = 0; i < newTools.length; i++){
TcModificationUtil.addPaths(toolMap, newTools[i], tcApplicability.fFolderInfoPaths);
}
if(tcApplicability.fFileInfoPaths.size() != 0){
FolderInfo foInfo = (FolderInfo)getResourceInfo();
IManagedProject mProj = foInfo.getParent().getManagedProject();
IProject project = mProj.getOwner().getProject();
Tool[] filtered = (Tool[])foInfo.filterTools(newTools, mProj);
if(filtered.length != 0){
for (IPath p : tcApplicability.fFileInfoPaths) {
boolean found = false;
String ext = p.getFileExtension();
if(ext == null)
ext = ""; //$NON-NLS-1$
for(int i = 0; i < filtered.length; i++){
if(filtered[i].buildsFileType(ext, project)){
TcModificationUtil.addPath(toolMap, filtered[i], p);
found = true;
break;
}
}
if(!found){
if (DbgTcmUtil.DEBUG){
DbgTcmUtil.println("no tools found for path " + p); //$NON-NLS-1$
}
}
}
} else if (DbgTcmUtil.DEBUG){
DbgTcmUtil.println("no filtered tools"); //$NON-NLS-1$
}
}
}
private IToolChain getDefaultToolChain(){
IResourceInfo rcInfo = getResourceInfo();
IToolChain defaultTc = null;
if (rcInfo.getPath().segmentCount() == 0) {
// 1.Per-project : change to the "default" tool-chain defined in the extension
// super-class of the project configuration. NOTE: the makefile project case might
// need a special handling in this case.
IConfiguration cfg = rcInfo.getParent();
IConfiguration extCfg = cfg.getParent();
defaultTc = extCfg.getToolChain();
if (defaultTc == null) {
if (cfg.getToolChain() != null) {
defaultTc = cfg.getToolChain().getSuperClass();
}
}
} else {
// 2.per-folder : change to the same tool-chain as the one used by the parent
// folder.
IFolderInfo parentFo = ((ResourceInfo)rcInfo).getParentFolderInfo();
IToolChain tc = parentFo.getToolChain();
defaultTc = ManagedBuildManager.getExtensionToolChain(tc);
}
if(defaultTc != null && defaultTc.getId().equals(ConfigurationDataProvider.PREF_TC_ID))
defaultTc = null;
return defaultTc;
}
@Override
public final void restoreDefaults() {
IToolChain tc = getDefaultToolChain();
if(tc != null){
setToolChain(tc, true);
}
}
}