backport hostside pnp RCL_2_4
authordadubrow
Mon, 01 Feb 2010 13:31:33 -0600
branchRCL_2_4
changeset 859 a163687f3d89
parent 858 1ef0dbc67108
child 860 fd6ae4e6e3d9
backport hostside pnp
core/com.nokia.cpp.utils.core/src/com/nokia/cpp/internal/api/utils/core/HostOS.java
core/com.nokia.cpp.utils.core/src/com/nokia/cpp/internal/api/utils/core/PathUtils.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/com.nokia.cpp.utils.core/src/com/nokia/cpp/internal/api/utils/core/HostOS.java	Mon Feb 01 13:31:33 2010 -0600
@@ -0,0 +1,81 @@
+/*
+* 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.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+package com.nokia.cpp.internal.api.utils.core;
+
+import java.io.File;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+
+
+/**
+ * Utilities used for portability between hosts.
+ * <p>
+ * NOTE: please keep this in sync with the org.eclipse.cdt.debug.edc version of this class!
+ */
+public class HostOS {
+	/** Is the host Windows? */
+	public static boolean IS_WIN32 = File.separatorChar == '\\';
+	/** Is the host some Unix variant? */
+	public static boolean IS_UNIX = File.separatorChar == '/';
+	/** Executable file extension */
+	public static final String EXE_EXT = IS_WIN32 ? ".exe" : "";
+	
+	/**
+	 * Ensure that the executable name mentioned is canonical for the machine.
+	 * This only affects Windows, currently, ensuring that an ".exe" is attached.
+	 * @param executablePath
+	 * @return updated path
+	 */
+	public static String canonicalizeExecutableName(String executable) {
+		if (IS_WIN32) {
+			IPath executablePath = new Path(executable);
+			String ext = executablePath.getFileExtension();
+			if (ext == null) {
+				executable += EXE_EXT;
+			}
+		}
+		return executable;
+	}
+
+	/**
+	 * Scan the PATH variable and see if the given binary is visible on
+	 * the PATH that will be used at runtime (with the default environment and overrides).
+	 * @param pathValue the expected Path 
+	 * @param program
+	 * @return IPath if program is on PATH, else <code>null</code>
+	 */
+	public static IPath findProgramOnPath(String program, String pathValue) {
+		
+		// be sure proper path/extension are present
+		program = HostOS.canonicalizeExecutableName(program);
+		
+		IPath path = null;
+		
+		IPath[] pathEntries = PathUtils.getPathEntries(pathValue);
+		for (IPath pathEntry : pathEntries) {
+			IPath testPath = pathEntry.append(program);
+			if (testPath.toFile().exists()) {
+				path = testPath;
+				break;
+			}
+		}
+		
+		return path;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/com.nokia.cpp.utils.core/src/com/nokia/cpp/internal/api/utils/core/PathUtils.java	Mon Feb 01 13:31:33 2010 -0600
@@ -0,0 +1,272 @@
+/*
+* 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.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+package com.nokia.cpp.internal.api.utils.core;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+
+/**
+ * These utilities handle some common portability issues when dealing with
+ * (absolute) paths which may be in a format intended for another operating system.  
+ * It also handles shortcomings in the org.eclipse.core.runtime.Path
+ * implementation, which is not able to construct a meaningful path from
+ * a Win32 path outside of Windows.
+ * <p>
+ * NOTE: please keep this in sync with the org.eclipse.cdt.debug.edc version of this class!
+ */
+public class PathUtils {
+
+	/**
+	 * Convert a variable constructed blindly for a Win32 environment into
+	 * Unix-like syntax.  This is typically used for PATH or lists
+	 * of paths where ';' is the entry separator and '\' is the 
+	 * path component separator.
+	 * <p>
+	 * NOTE: we assume that the entries in the
+	 * path list are already legal Unix paths, but just with the
+	 * wrong slash.
+	 * @param env
+	 * @return converted string
+	 */
+	public static String convertPathListToUnix(String env) {
+		if (env == null) return null;
+		env = env.replaceAll(";", ":");  // entry separators
+		env = env.replaceAll("\\\\", "/");  // path separators
+		return env;
+	}
+
+	/**
+	 * Convert a path constructed blindly for a Win32 environment into
+	 * Unix-like syntax.  <p>
+	 * NOTE: we assume that the path is already a legal Unix path, 
+	 * but just with the wrong slash.
+	 * @param file
+	 * @return converted string
+	 */
+	public static String convertPathToUnix(String file) {
+		if (file == null) return null;
+		// handle Windows slashes and canonicalize
+		file = file.replaceAll("\\\\", "/");
+		return file;
+	}
+
+	/**
+	 * Convert a path which may be in Windows or Unix format to Windows format.
+	 * NOTE: we assume that the path is already a legal path, 
+	 * but just with the wrong slash.
+	 * @param file
+	 * @return converted string
+	 */
+	public static String convertPathToWindows(String file) {
+		if (file == null) return null;
+		file = file.replaceAll("/", "\\\\");
+		return file;
+	}
+
+	/**
+	 * Convert a path which may be in Windows or Unix format to Windows format.
+	 * NOTE: we assume that the path is already a legal path, 
+	 * but just with the wrong slash.
+	 * @param file
+	 * @return converted string
+	 */
+	public static String convertPathToWindows(IPath path) {
+		return convertPathToWindows(path.toPortableString());
+	}
+
+	/**
+	 * Convert a path which may be in the opposite slash format to the local slash format.
+	 * NOTE: we assume that the path is already a legal path, 
+	 * but just with the wrong slash.
+	 * @param file
+	 * @return converted string
+	 */
+	public static String convertPathToNative(String path) {
+		if (path == null) return null;
+		if (HostOS.IS_UNIX)
+			return path.replaceAll("\\\\", "/");
+		else
+			return path.replaceAll("/", "\\\\");
+	}
+
+	/**
+	 * Create an IPath from a string which may be a Win32 path. <p>
+	 * <p>
+	 * ("new Path(...)" won't work in Unix when using a Win32 path: the backslash
+	 * separator and the device notation are completely munged.)
+	 * @param path
+	 * @return converted string
+	 */
+	public static IPath createPath(String path) {
+		if (path == null) return null;
+		if (path.contains("\\")) {
+			// handle Windows slashes and canonicalize
+			path = path.replaceAll("\\\\", "/");
+		}
+		
+		// also check for device or UNC
+		int idx = path.indexOf(":");
+		if (idx > 0) {
+			String device = path.substring(0, idx + 1);
+			path = path.substring(idx + 1);
+			return new Path(path).setDevice(device);
+		} 
+		else {
+			// Cygwin or UNC path
+			if (path.startsWith("//")) {
+				String network;
+				idx = path.indexOf("/", 2);
+				if (idx > 0) {
+					network = path.substring(0, idx);
+					path = path.substring(idx);
+				} else {
+					network = path;
+					path = "";
+				}
+				return new Path(network, path).makeUNC(true);
+			}
+		}		
+		
+		// fallthrough
+		return new Path(path);
+	}
+
+	/**
+	 * Get the PATH entries from the given path environment value or the
+	 * system environment.
+	 * @param pathValue the expected PATH/Path value, or <code>null</code> for the system value
+	 * @return array of IPath, never <code>null</code>
+	 */
+	public static IPath[] getPathEntries(String pathValue) {
+		String pathVar = null;
+		if (pathValue != null) {
+			pathVar = pathValue;
+		} else {
+			if (HostOS.IS_WIN32) {
+				// canonical name, plus fallback below
+				pathVar = System.getenv("Path"); //$NON-NLS-1$
+			}
+			if (pathVar == null) {
+				pathVar = System.getenv("PATH"); //$NON-NLS-1$
+			}
+		}
+		
+		if (pathVar == null)
+			pathVar = "";
+		
+		String pathSeparator = System.getProperty("path.separator");
+		String[] pathEntries = pathVar.split(pathSeparator);
+		IPath[] paths = new IPath[pathEntries.length];
+		for (int i = 0; i < pathEntries.length; i++) {
+			paths[i] = new Path(pathEntries[i]);
+		}
+		return paths;
+	}
+
+	/**
+	 * If the filesystem is case sensitive, locate the file on the filesystem 
+	 * on the given path, by ignoring case sensitivity differences.  
+	 * This is needed on case-preserving but not case-insensitive filesystems.
+	 * @param path 
+	 * @return path pointing to existing file (possibly with different case in components) or
+	 * original path if there is no match
+	 */
+	public static IPath findExistingPathIfCaseSensitive(IPath path) {
+		// case is insensitive already
+		if (HostOS.IS_WIN32)
+			return path;
+		
+		if (path == null || !path.isAbsolute())
+			return path;
+		
+		File pathFile = path.toFile();
+		if (pathFile.exists()) {
+			try {
+				return new Path(pathFile.getCanonicalPath());
+			} catch (IOException e) {
+				// should not happen
+				return path;
+			}
+		}
+			
+
+		// start with the assumption that the path is mostly correct except for the
+		// last N segments.
+		IPath goodPath = Path.ROOT;
+		if (path.getDevice() != null)
+			goodPath = goodPath.setDevice(path.getDevice());
+		
+		// if bad drive or no root (?!), just skip
+		if (!goodPath.toFile().exists())
+			return path;
+		
+		for (int seg = path.segmentCount(); seg > 0; seg--) {	
+			final IPath prefix = path.uptoSegment(seg - 1);
+
+			if (prefix.toFile().exists()) {
+				goodPath = prefix;
+				break;
+			}
+		}
+		
+		StringBuilder builder = new StringBuilder();
+		
+		builder.append(goodPath.addTrailingSeparator().toOSString());
+		
+		boolean failedLookup = false;
+		
+		for (int seg = goodPath.segmentCount(); seg < path.segmentCount(); seg++) {
+			final String segment = path.segment(seg);
+			
+			final String[] matches = { segment };
+			
+			if (!failedLookup) {
+				File dir = new File(builder.toString());
+				if (!new File(dir, matches[0]).exists()) {
+					// component has wrong case; find the first one matching case-insensitively
+					String[] names = dir.list(new FilenameFilter() {
+						
+						public boolean accept(File dir, String name) {
+							if (name.equalsIgnoreCase(segment)) {
+								matches[0] = name;
+								return true;
+							}
+							return false;
+						}
+					});
+					
+					if (names.length == 0) {
+						// no matches!  the rest of the path won't match either
+						failedLookup = true;
+					}
+				}
+			}
+			builder.append(matches[0]);
+			builder.append('/');
+		}
+		
+		if (!path.hasTrailingSeparator() && builder.length() > 0 && builder.charAt(builder.length() - 1) == '/') {
+			builder.setLength(builder.length() - 1);
+		}
+		return new Path(builder.toString());
+	}
+}