sbsv2/raptor/python/generic_path.py
changeset 590 360bd6b35136
parent 0 044383f39525
--- a/sbsv2/raptor/python/generic_path.py	Wed Jun 16 16:51:40 2010 +0300
+++ b/sbsv2/raptor/python/generic_path.py	Wed Jun 23 16:56:47 2010 +0800
@@ -1,315 +1,346 @@
-#
-# Copyright (c) 2006-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: 
-# generic_path module
-#
-
-import os
-import sys
-import re
-import types
-
-# are we on windows, and if so what is the current drive letter
-isWin = sys.platform.lower().startswith("win")
-if isWin:
-	drive = re.match('^([A-Za-z]:)',os.getcwd()).group(0)
-
-# regex for "bare" drive letters	
-driveRE = re.compile('^[A-Za-z]:$')
-
-# Base class
-
-class Path:
-	"""This class represents a file path.
-	
-	A generic path object supports operations without needing to know
-	about Windows and Linux differences. The standard str() function can
-	obtain a string version of the path in Local format for use by
-	platform-specific functions (file opening for example).
-	
-	We use forward slashes as path separators (even on Windows).
-	
-	For example,
-	
-		path1 = generic_path.Path("/foo")
-		path2 = generic_path.Path("bar", "bing.bang")
-		
-		print str(path1.Append(path2))
-		
-	Prints /foo/bar/bing.bang		on Linux
-	Prints c:/foo/bar/bing.bang		on Windows (if c is the current drive)
-	""" 
-		
-	def __init__(self, *arguments):
-		"""construct a path from a list of path elements"""
-		
-		if len(arguments) == 0:
-			self.path = ""
-			return
-		
-		list = []
-		for i,arg in enumerate(arguments):
-			if isWin:
-				if i == 0:
-					# If the first element starts with \ or / then we will
-					# add the current drive letter to make a fully absolute path
-					if arg.startswith("\\\\"):
-						list.append(arg) # A UNC path - don't mess with it
-					elif arg.startswith("\\") or arg.startswith("/"):
-						list.append(drive + arg)
-					# If the first element is a bare drive then dress it with a \
-					# temporarily otherwise "join" will not work properly.
-					elif driveRE.match(arg):
-						list.append(arg + "\\")
-					# nothing special about the first element
-					else:
-						list.append(arg)
-				else:
-					if arg.startswith("\\\\"):
-						raise ValueError("non-initial path components must not start with \\\\ : %s" % arg)
-					else:
-						list.append(arg)
-				if ";" in arg:
-					raise ValueError("An individual windows Path may not contain ';' : %s" % arg)
-			else:
-				list.append(arg)
-	
-		self.path = os.path.join(*list)
-		
-		# normalise to avoid nastiness with dots and multiple separators
-		# but do not normalise "" as it will become "."
-		if self.path != "":
-			self.path = os.path.normpath(self.path)
-		
-		# always use forward slashes as separators
-		self.path = self.path.replace("\\", "/")
-		
-		# remove trailing slashes unless we are just /
-		if self.path != "/":
-			self.path = self.path.rstrip("/")
-		
-	def __str__(self):
-		return self.path
-	
-	def GetNeutralStr(self):
-		"""return the path as a string that could be included in other paths."""
-		return self.path.replace(":","").replace("/","")
-
-	def GetLocalString(self):
-		"""return a string in the local file-system format.
-		
-		e.g. C:/tmp on Windows or /C/tmp on Linux"""
-		return self.path
-	
-	def isAbsolute(self):
-		"test whether this path is absolute or relative"
-		# C: is an absolute directory
-		return (os.path.isabs(self.path) or driveRE.match(self.path))
-	
-	def Absolute(self):
-		"""return an object for the absolute version of this path.
-		
-		Prepends the current working directory to relative paths and
-		the current drive (on Windows) to /something type paths."""
-		# leave C: alone as abspath will stick the cwd on
-		if driveRE.match(self.path):
-			return Path(self.path)
-		else:
-			return Path(os.path.abspath(self.path))
-	
-	def Append(self, *arguments):
-		"return an object with path elements added at the end of this path"
-		return Join(*((self,) + arguments))
-	
-	def Prepend(self, *arguments):
-		"return an object with path elements added at the start of this path"
-		return Join(*(arguments + (self,)))
-	
-	def isDir(self):
-		"test whether this path points to an existing directory"
-		# C: is a directory
-		return (os.path.isdir(self.path) or driveRE.match(self.path))
-	
-	def isFile(self):
-		"test whether this path points to an existing file"
-		return os.path.isfile(self.path)
-
-	def Exists(self):
-		"test whether this path exists in the filesystem"
-		if driveRE.match(self.path):
-			return os.path.exists(self.path + "/")
-		else:
-			return os.path.exists(self.path)
-		
-	def Dir(self):
-		"return an object for the directory part of this path"
-		if driveRE.match(self.path):
-			return Path(self.path)
-		else:
-			return Path(os.path.dirname(self.path))
-
-	def File(self):
-		"return a string for the file part of this path"
-		return os.path.basename(self.path)
-
-	def Components(self):
-		"""return a list of the components of this path."""
-		return self.path.split('/')
-
-	def FindCaseless(self):
-		"""Given a path which may not be not correct in terms of case,
-		search the filesystem to find the corresponding, correct path.
-		paths are assumed to be absolute and normalised (which they
-		should be in this class).
-
-		Assumes that the path is more right than wrong, i.e. starts
-		with the full path and tests for existence - then takes the
-		last component off and check for that.
-
-		This will be inefficient if used in cases where the file 
-		has a high probability of not existing.
-		"""
-
-		if os.path.exists(self.path):
-			return Path(self.path)
-
-		unknown_elements = []
-		tail = self.path
-		head = None
-		while tail != '': 
-			if os.path.exists(tail):
-				break
-			else:
-				(tail,head) = os.path.split(tail)
-				#print "(head,tail) = (%s,%s)\n" % (head,tail)
-				unknown_elements.append(head)
-
-		if tail == None:
-			result = ""
-		else:
-			result = tail
-
-		# Now we know the bits that may be wrong so we can search for them
-		unknown_elements.reverse()
-		for item in unknown_elements:
-			possible = os.path.join(result, item) 
-			if os.path.exists(possible):
-				result = possible
-				continue # not finished yet - only this element is ok
-
-			# Nope, we really do have to search for this component of the path
-			possible = None
-			if result:
-				for file in os.listdir(result):
-					if file.lower() == item.lower():
-						possible = os.path.join(result,file)
-						break # find first matching name (might not be right)
-				if possible is None:
-					result = "" 
-					break # really couldn't find the file
-				result = possible
-
-		if result == "":
-			return None
-
-		return Path(result)
-
-	def From(self,source):
-		"""Returns the relative path from 'source' to here."""
-		list1 = source.Absolute().Components()
-		list2 = self.Absolute().Components()
-
-		# on windows if the drives are different
-		# then the relative path is the absolute one.
-		if isWin and list1[0] != list2[0]:
-			return self.Absolute()
-
-		final_list = []
-		for item in list1:
-			if list2 != []:
-				for widget in list2:
-					if item == widget:
-						list2.pop(0)
-						break
-					else:
-						final_list.insert(0, "..")
-						final_list.append(widget)
-						list2.pop(0)
-						break
-			else:
-				final_list.insert(0, "..")
-
-		final_list.extend(list2)
-
-		return Join(*final_list)
-
-	def GetShellPath(self):
-		"""Returns correct slashes according to os type as a string
-		"""
-		if isWin:
-			if  "OSTYPE" in os.environ and os.environ['OSTYPE'] == "cygwin" :
-				return self.path
-
-			return self.path.replace("/", "\\")
-
-		return self.path
-
-
-# Module functions
-
-def Join(*arguments):
-	"""Concatenate the given list to make a generic path object. 
-	
-	This can accept both strings and Path objects, and join
-	them "intelligently" to make a complete path."""
-	list = []
-	for arg in arguments:
-		if isinstance(arg, Path):
-			list.append(arg.path)
-		else:
-			list.append(arg)
-		
-	return Path(*list)
-
-def CurrentDir():
-	"return a Path object for the current working directory"
-	return Path(os.getcwd())
-
-def NormalisePathList(aList):
-	"""Convert a list of strings into a list of Path objects"""
-	return map(lambda x: Path(x), aList)
-
-def Where(afile):
-	"""Return the location of a file 'afile' in the system path.
-	
-	On windows, adds .exe onto the filename if it's not there. Returns the first location it found or None if it wasn't found.
-	
-	>>> Where("python")
-	"/usr/bin/python"
-	>>> Where("nonexistentfile")
-	None
-	"""
-	location = None
-	if sys.platform.startswith("win"):
-		if not afile.lower().endswith(".exe"):
-			afile += ".exe"
-			
-	for current_file in [os.path.join(loop_number,afile) for loop_number in
-			     os.environ["PATH"].split(os.path.pathsep)]:
-		if os.path.isfile(current_file):
-			location = current_file
-			break
-	return location
-
-# end of generic_path module
+#
+# Copyright (c) 2006-2010 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: 
+# generic_path module
+#
+
+import os
+import sys
+import re
+import types
+import ctypes
+
+# are we on windows, and if so what is the current drive letter
+isWin = sys.platform.lower().startswith("win")
+if isWin:
+	drive = re.match('^([A-Za-z]:)',os.getcwd()).group(0)
+
+# regex for "bare" drive letters	
+driveRE = re.compile('^[A-Za-z]:$')
+
+# Base class
+
+class Path:
+	"""This class represents a file path.
+	
+	A generic path object supports operations without needing to know
+	about Windows and Linux differences. The standard str() function can
+	obtain a string version of the path in Local format for use by
+	platform-specific functions (file opening for example).
+	
+	We use forward slashes as path separators (even on Windows).
+	
+	For example,
+	
+		path1 = generic_path.Path("/foo")
+		path2 = generic_path.Path("bar", "bing.bang")
+		
+		print str(path1.Append(path2))
+		
+	Prints /foo/bar/bing.bang		on Linux
+	Prints c:/foo/bar/bing.bang		on Windows (if c is the current drive)
+	""" 
+		
+	def __init__(self, *arguments):
+		"""construct a path from a list of path elements"""
+		
+		if len(arguments) == 0:
+			self.path = ""
+			return
+		
+		list = []
+		for i,arg in enumerate(arguments):
+			if isWin:
+				if i == 0:
+					# If the first element starts with \ or / then we will
+					# add the current drive letter to make a fully absolute path
+					if arg.startswith("\\\\"):
+						list.append(arg) # A UNC path - don't mess with it
+					elif arg.startswith("\\") or arg.startswith("/"):
+						list.append(drive + arg)
+					# If the first element is a bare drive then dress it with a \
+					# temporarily otherwise "join" will not work properly.
+					elif driveRE.match(arg):
+						list.append(arg + "\\")
+					# nothing special about the first element
+					else:
+						list.append(arg)
+				else:
+					if arg.startswith("\\\\"):
+						raise ValueError("non-initial path components must not start with \\\\ : %s" % arg)
+					else:
+						list.append(arg)
+				if ";" in arg:
+					raise ValueError("An individual windows Path may not contain ';' : %s" % arg)
+			else:
+				list.append(arg)
+	
+		self.path = os.path.join(*list)
+		
+		# normalise to avoid nastiness with dots and multiple separators
+		# but do not normalise "" as it will become "."
+		if self.path != "":
+			self.path = os.path.normpath(self.path)
+		
+		# always use forward slashes as separators
+		self.path = self.path.replace("\\", "/")
+		
+		# remove trailing slashes unless we are just /
+		if self.path != "/":
+			self.path = self.path.rstrip("/")
+		
+	def __str__(self):
+		return self.path
+	
+	def GetNeutralStr(self):
+		"""return the path as a string that could be included in other paths."""
+		return self.path.replace(":","").replace("/","")
+
+	def GetLocalString(self):
+		"""return a string in the local file-system format.
+		
+		e.g. C:/tmp on Windows or /C/tmp on Linux"""
+		return self.path
+	
+	def isAbsolute(self):
+		"test whether this path is absolute or relative"
+		# C: is an absolute directory
+		return (os.path.isabs(self.path) or driveRE.match(self.path))
+	
+	def Absolute(self):
+		"""return an object for the absolute version of this path.
+		
+		Prepends the current working directory to relative paths and
+		the current drive (on Windows) to /something type paths."""
+		# leave C: alone as abspath will stick the cwd on
+		if driveRE.match(self.path):
+			return Path(self.path)
+		else:
+			return Path(os.path.abspath(self.path))
+	
+	def Append(self, *arguments):
+		"return an object with path elements added at the end of this path"
+		return Join(*((self,) + arguments))
+	
+	def Prepend(self, *arguments):
+		"return an object with path elements added at the start of this path"
+		return Join(*(arguments + (self,)))
+	
+	def isDir(self):
+		"test whether this path points to an existing directory"
+		# C: is a directory
+		return (os.path.isdir(self.path) or driveRE.match(self.path))
+	
+	def isFile(self):
+		"test whether this path points to an existing file"
+		return os.path.isfile(self.path)
+
+	def Exists(self):
+		"test whether this path exists in the filesystem"
+		if driveRE.match(self.path):
+			return os.path.exists(self.path + "/")
+		else:
+			return os.path.exists(self.path)
+		
+	def Dir(self):
+		"return an object for the directory part of this path"
+		if driveRE.match(self.path):
+			return Path(self.path)
+		else:
+			return Path(os.path.dirname(self.path))
+
+	def File(self):
+		"return a string for the file part of this path"
+		return os.path.basename(self.path)
+
+	def Components(self):
+		"""return a list of the components of this path."""
+		return self.path.split('/')
+
+	def FindCaseless(self):
+		"""Given a path which may not be not correct in terms of case,
+		search the filesystem to find the corresponding, correct path.
+		paths are assumed to be absolute and normalised (which they
+		should be in this class).
+
+		Assumes that the path is more right than wrong, i.e. starts
+		with the full path and tests for existence - then takes the
+		last component off and check for that.
+
+		This will be inefficient if used in cases where the file 
+		has a high probability of not existing.
+		"""
+
+		if os.path.exists(self.path):
+			return Path(self.path)
+
+		unknown_elements = []
+		tail = self.path
+		head = None
+		while tail != '': 
+			if os.path.exists(tail):
+				break
+			else:
+				(tail,head) = os.path.split(tail)
+				#print "(head,tail) = (%s,%s)\n" % (head,tail)
+				unknown_elements.append(head)
+
+		if tail == None:
+			result = ""
+		else:
+			result = tail
+
+		# Now we know the bits that may be wrong so we can search for them
+		unknown_elements.reverse()
+		for item in unknown_elements:
+			possible = os.path.join(result, item) 
+			if os.path.exists(possible):
+				result = possible
+				continue # not finished yet - only this element is ok
+
+			# Nope, we really do have to search for this component of the path
+			possible = None
+			if result:
+				for file in os.listdir(result):
+					if file.lower() == item.lower():
+						possible = os.path.join(result,file)
+						break # find first matching name (might not be right)
+				if possible is None:
+					result = "" 
+					break # really couldn't find the file
+				result = possible
+
+		if result == "":
+			return None
+
+		return Path(result)
+
+	def From(self,source):
+		"""Returns the relative path from 'source' to here."""
+		list1 = source.Absolute().Components()
+		list2 = self.Absolute().Components()
+
+		# on windows if the drives are different
+		# then the relative path is the absolute one.
+		if isWin and list1[0] != list2[0]:
+			return self.Absolute()
+
+		final_list = []
+		for item in list1:
+			if list2 != []:
+				for widget in list2:
+					if item == widget:
+						list2.pop(0)
+						break
+					else:
+						final_list.insert(0, "..")
+						final_list.append(widget)
+						list2.pop(0)
+						break
+			else:
+				final_list.insert(0, "..")
+
+		final_list.extend(list2)
+
+		return Join(*final_list)
+
+	def GetShellPath(self):
+		"""Returns correct slashes according to os type as a string
+		"""
+		if isWin:
+			if  "OSTYPE" in os.environ and os.environ['OSTYPE'] == "cygwin" :
+				return self.path
+
+			return self.path.replace("/", "\\")
+
+		return self.path
+
+	def GetSpaceSafePath(self):
+		"""Returns a version of the path where spaces don't interfere with shell interpretation.
+		
+		This functionality only applies to Windows - paths containing spaces are assumed to be problematic
+		on non-Windows platforms.
+		
+		On Windows, the path is returned in Windows-specific 8.3 short path form - tilde are used to replace
+		spaces and fit path elements within 8.3 requirements.  As 8.3 format paths are not guaranteed to be
+		supported on all Windows installs, and can only be calculated if they exist, a newly formated path is
+		only returned if it is returned by the Windows API and tested to exist.
+		"""
+		
+		if not isWin:
+			return None
+		
+		from ctypes.wintypes import DWORD, LPSTR, MAX_PATH
+
+		GetShortPathNameA = ctypes.windll.kernel32.GetShortPathNameA
+		GetShortPathNameA.restype = DWORD
+		GetShortPathNameA.argtypes = LPSTR, LPSTR, DWORD
+		
+		buffer = ctypes.create_string_buffer(MAX_PATH)
+		GetShortPathNameA(self.path, buffer, MAX_PATH)
+		
+		spacesafe = buffer.value
+		
+		if not spacesafe or not os.path.exists(spacesafe):
+			return None
+		
+		return spacesafe
+		
+# Module functions
+
+def Join(*arguments):
+	"""Concatenate the given list to make a generic path object. 
+	
+	This can accept both strings and Path objects, and join
+	them "intelligently" to make a complete path."""
+	list = []
+	for arg in arguments:
+		if isinstance(arg, Path):
+			list.append(arg.path)
+		else:
+			list.append(arg)
+		
+	return Path(*list)
+
+def CurrentDir():
+	"return a Path object for the current working directory"
+	return Path(os.getcwd())
+
+def NormalisePathList(aList):
+	"""Convert a list of strings into a list of Path objects"""
+	return map(lambda x: Path(x), aList)
+
+def Where(afile):
+	"""Return the location of a file 'afile' in the system path.
+	
+	On windows, adds .exe onto the filename if it's not there. Returns the first location it found or None if it wasn't found.
+	
+	>>> Where("python")
+	"/usr/bin/python"
+	>>> Where("nonexistentfile")
+	None
+	"""
+	location = None
+	if sys.platform.startswith("win"):
+		if not afile.lower().endswith(".exe"):
+			afile += ".exe"
+			
+	for current_file in [os.path.join(loop_number,afile) for loop_number in
+			     os.environ["PATH"].split(os.path.pathsep)]:
+		if os.path.isfile(current_file):
+			location = current_file
+			break
+	return location
+
+# end of generic_path module