core/com.nokia.carbide.cpp.sdk.core/src/com/nokia/carbide/cpp/internal/api/sdk/SBSv2Utils.java
author timkelly
Fri, 12 Feb 2010 09:56:50 -0600
changeset 945 67437bfc7c6f
parent 693 2d475d296af4
child 1134 081b99cb271a
permissions -rw-r--r--
Add ISymbianManagerLoadedHook - currently used to notify com.nokia.qt plugins that need to ensure that Qt SDKs have been scanned and added to the Qt preferences and that ICarbideBuildConfiguration listeners are added so the proper Qt-SDK can be set with build config changes. Scanned Qt SDKs are wrapped in a Job and added SDKs are reported to the Error log as Info.

/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
*/
package com.nokia.carbide.cpp.internal.api.sdk;

import java.io.File;
import java.io.FileFilter;
import java.text.MessageFormat;
import java.util.*;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.eclipse.cdt.utils.spawner.EnvironmentReader;
import org.eclipse.core.filesystem.URIUtil;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.osgi.framework.Version;
import org.osgi.service.prefs.BackingStoreException;
import org.w3c.dom.*;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.DefaultHandler;

import com.nokia.carbide.cpp.sdk.core.*;
import com.nokia.cpp.internal.api.utils.core.FileUtils;
import com.nokia.cpp.internal.api.utils.core.HostOS;
import com.nokia.cpp.internal.api.utils.core.Logging;

/**
 * Utility class for SBSv2
 * @since 2.0
 */
public class SBSv2Utils {

	private static final String SBSV2_FILTERED_CONFIGS_STORE = "sbsv2FilteredConfigs"; //$NON-NLS-1$
	private static final String SBSV2_FILTERED_CONFIGS_DELIMETER = ";"; //$NON-NLS-1$

	private static List<String> unfilteredSBSv2ConfigNames;

	protected static final String SBS_HOME = "SBS_HOME";
	protected static String sbsHome;
	protected static IPath sbsPath;

	private static boolean scannedSbsState = false;
	private static final String sbsScriptName = HostOS.IS_WIN32 ? "sbs.bat" : "sbs"; 
	
	/**
     * Get the path to the SBSv2 bin directory.  This is based on the SBS_HOME environment variable
     * and may or may not actually exist.
     * @return absolute path to the bin directory, or null if SBS_HOME is not set
     */
    public static IPath getSBSBinDirectory() {
    	String sbsHome = EnvironmentReader.getEnvVar("SBS_HOME"); //$NON-NLS-1$
    	if (sbsHome != null) {
    		return new Path(sbsHome).append("bin"); //$NON-NLS-1$
    	}
    	return null;
    }

    /**
     * Get the build configurations supported by SBSv2
     * @param refreshList whether or not to parse the configuration xml files again
     * @return list of configuration names, never null
     */
    public static List<String> getUnfilteredSBSv2BuildConfigurations(boolean refreshList) {
    	
    	if (unfilteredSBSv2ConfigNames == null || refreshList) {
    		unfilteredSBSv2ConfigNames = new ArrayList<String>();
    		
        	// parse the xml files in SBS_HOME/lib/config/ to get SBSv2 configs
    		try {

    			IPath configPath = getSBSBinDirectory();
    			if (configPath != null) {
    				configPath = configPath.removeLastSegments(1).append("lib/config"); //$NON-NLS-1$
    				File configDir = configPath.toFile();
    				if (configDir.exists() && configDir.isDirectory()) {
    					File[] configFiles = FileUtils.listFilesInTree(configDir, new FileFilter() {

    						public boolean accept(File arg0) {
    							if (arg0.isDirectory()) {
    								return true;
    							}
    							return arg0.getName().toLowerCase().endsWith("xml"); //$NON-NLS-1$
    						}
    						
    					}, false);
    					
    					for (File file : configFiles) {
    						getConfigsForFile(file);
    					}
    				}
    			}

    		} catch (Exception e) {
        		e.printStackTrace();
        		Logging.log(SDKCorePlugin.getDefault(), Logging.newStatus(SDKCorePlugin.getDefault(), e));
    		}
    	}
    	
    	return unfilteredSBSv2ConfigNames;
	}

    /**
     * Given a list of SDKs, returns the list of the SDK's supported by SBSv2
     * @param sdks list of SDK's to check
     * @return list of SBSv2 supported SDK's, may be empty
     */
    public static List<ISymbianSDK> getSupportedSDKs(List<ISymbianSDK> sdks) {
    	List<ISymbianSDK> supportedSDKs = new ArrayList<ISymbianSDK>();

    	// If there is no SBSv1 builder, then assume all SDKs are SBSv2 capable
    	if (!enableSBSv1Support()) {
    		supportedSDKs.addAll(sdks);
    	} else {
	    	//TODO need a better way to do this from Symbian.
	    	// For now, just filter out anything older than 9.4
	    	for (ISymbianSDK sdk : sdks) {
	    		Version osVersion = sdk.getOSVersion();
	    		if (osVersion.getMajor() > 8 ||
	    				(osVersion.getMajor() == 8 && osVersion.getMinor() > 3)) {
	    			supportedSDKs.add(sdk);
	    		}
	    	}
    	}
    	return supportedSDKs;
    }
    
	/**
	 * Returns the list of SBSv2 build configuration names that should
	 * be filtered out of any UI
	 */
	public static String[] getSBSv2ConfigurationsToFilter() {
		IEclipsePreferences prefs = new InstanceScope().getNode(SDKCorePlugin.PLUGIN_ID);
		if (prefs != null) {
			String configs = prefs.get(SBSV2_FILTERED_CONFIGS_STORE, "");
			return configs.split(SBSV2_FILTERED_CONFIGS_DELIMETER);
		}
		return new String[0];
	}

	/**
	 * Set the list of SBSv2 build configurations that should be filtered
	 * out of any UI
	 * @param configs configs to be filtered
	 */
	public static void setSBSv2ConfigurationsToFilter(String[] configs) {
		IEclipsePreferences prefs = new InstanceScope().getNode(SDKCorePlugin.PLUGIN_ID);
		if (prefs != null) {
			String store = ""; //$NON-NLS-1$
			for (String config : configs) {
				store = store + SBSV2_FILTERED_CONFIGS_DELIMETER + config;
			}
			
			// remove the leading delimeter
			if (store.length() > 0) {
				store = store.substring(1);
			}
			if (store.length() >= 0){
				// lenght of zero means there are not configs to filter (or show them all)
				prefs.put(SBSV2_FILTERED_CONFIGS_STORE, store);
				try {
					prefs.flush();
				} catch (BackingStoreException e) {
					Logging.log(SDKCorePlugin.getDefault(),
							Logging.newStatus(SDKCorePlugin.getDefault(), e));
				}
			}
		}
	}

	/**
	 * Gets the list of SBSv2 build contexts for the given SDK
	 * @param sdk the SDK to get the build contexts for
	 * @return the list of SBSv2 build contexts.  the list may be empty
	 */
	public static List<ISymbianBuildContext> getFilteredSBSv2BuildContexts(ISymbianSDK sdk) {
		List<ISymbianBuildContext> contexts = new ArrayList<ISymbianBuildContext>();
		
		for (String name : getUnfilteredSBSv2BuildConfigurations(false)) {

			boolean addConfig = true;
			for (String filteredConfig : getSBSv2ConfigurationsToFilter()) {
				if (filteredConfig.compareTo(name) == 0) {
					addConfig = false;
					break;
				}
			}

			if (addConfig) {
				// only support configs that fall into something we can make a build context
				// out of.  They must have a platform and a target.
				String targetString = null;
		    	if (name.toLowerCase().endsWith("_udeb") || name.toLowerCase().endsWith("_deb")) { //$NON-NLS-1$ //$NON-NLS-2$
		    		targetString = ISymbianBuildContext.DEBUG_TARGET;
		    	} else if (name.toLowerCase().endsWith("_urel") || name.toLowerCase().endsWith("_rel")) { //$NON-NLS-1$ //$NON-NLS-2$
		    		targetString = ISymbianBuildContext.RELEASE_TARGET;
		    	}
		    	
		    	if (targetString != null) {
		    		String[] parts = name.split("_"); //$NON-NLS-1$
		    		if (parts.length == 2) {
		    			SymbianBuildContext context = new SymbianBuildContext(sdk, parts[0].toUpperCase(), targetString);
		    			contexts.add(context);
		    		}
		    	}
			}
		}
		
		Collections.sort(contexts, new Comparator<ISymbianBuildContext>() {

			public int compare(ISymbianBuildContext o1, ISymbianBuildContext o2) {
				String platform1 = o1.getPlatformString();
				String platform2 = o2.getPlatformString();
				if (platform1.equals(platform2)) {
					return o1.getTargetString().compareTo(o2.getTargetString());
				} else {
					if (platform1.equals(ISymbianBuildContext.EMULATOR_PLATFORM)) {
						return -1;
					}
					else if (platform2.equals(ISymbianBuildContext.EMULATOR_PLATFORM)) {
						return 1;
					}
				}
				return 0;
			}
			
		});

		return contexts;
	}

	/**
	 * Whether or not to display SBSv1 builder UI
	 * @return true if SBSv1 is available, false otherwise
	 */
	public static boolean enableSBSv1Support() {
		if (!enableSBSv2Support())
			return true;
		
		// TODO LINUX: more accurate check
		if (HostOS.IS_WIN32)
			return true;
		return false;
	}
	
	/**
	 * Whether or not to display SBSv2 builder UI
	 * @return true if SBSv2 is installed, false otherwise
	 */
	public static boolean enableSBSv2Support() {
		IPath sbsBinPath = getSBSBinDirectory();
		if (sbsBinPath != null && sbsBinPath.toFile().exists()) {
			return true;
		}
		return false;
	}

	private static void getConfigsForFile(File file) {
    	
    	try {
    		Element root = null;
    		DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    		parser.setErrorHandler(new DefaultHandler());

    		InputSource source = new InputSource(URIUtil.toURI(file.getAbsolutePath()).getPath());
    		root = parser.parse(source).getDocumentElement();
    		
    		NodeList children = root.getChildNodes();
    		for (int i=0; i< children.getLength(); i++) {
    			getConfigsForNode(children.item(i));
    		}
    		
    	} catch (Exception e) {
    		e.printStackTrace();
    		Logging.log(SDKCorePlugin.getDefault(), Logging.newStatus(SDKCorePlugin.getDefault(), e));
    	}
    }
    
    private static void getConfigsForNode(Node node) {
		if (node.getNodeName().equals("config")) { //$NON-NLS-1$
			Node abstractNode = node.getAttributes().getNamedItem("abstract");  //$NON-NLS-1$
			if (abstractNode == null || abstractNode.getNodeValue().equals("false")) { //$NON-NLS-1$
				Node namedNode = node.getAttributes().getNamedItem("name"); //$NON-NLS-1$
				if (namedNode != null) {
					// only support configs that fall into something we can make a build context
					// out of.  They must have a platform and a target.
					String configName = namedNode.getNodeValue();
			    	if (configName.toLowerCase().endsWith("_udeb") || configName.toLowerCase().endsWith("_deb") || //$NON-NLS-1$ //$NON-NLS-2$
		    			configName.toLowerCase().endsWith("_urel") || configName.toLowerCase().endsWith("_rel")) { //$NON-NLS-1$ //$NON-NLS-2$
			    		if (configName.split("_").length == 2) { //$NON-NLS-1$
							unfilteredSBSv2ConfigNames.add(configName);
			    		}
			    	}
				}
			}

			NodeList children = node.getChildNodes();
			for (int i=0; i< children.getLength(); i++) {
				getConfigsForNode(children.item(i));
			}
		}
    }

	/**
	 * (Re-)scan the SBSv2 / Raptor configuration
	 * @return message if error, else null
	 */
	public static String scanSBSv2() {
		// do some basic checks
		sbsHome = System.getenv(SBS_HOME);
		if (sbsHome == null) {
			return Messages.getString("SBSv2Utils.DefineSBS_HOMEMessage"); //$NON-NLS-1$
		}
		
		IPath expectedPath = new Path(sbsHome).append("bin").append(sbsScriptName);
		if (expectedPath.toFile().exists()) {
			sbsPath = expectedPath;
		} else {
			sbsPath = HostOS.findProgramOnPath(sbsScriptName, null);
			if (sbsPath == null) {
				return MessageFormat.format(
								Messages.getString("SBSv2Utils.CannotFindSBSScriptError"), //$NON-NLS-1$
								sbsScriptName);
			}
		}
		
		return null;
	}

    /**
     * Get the path to SBSv2 (sbs.bat or sbs)
     */
	public static IPath getSBSPath() {
		if (!scannedSbsState) {
			scanSBSv2();
			scannedSbsState = true;
		}
		return sbsPath != null ? sbsPath : new Path(sbsScriptName);  // dummy
	}

}