--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/releasing/blocks/cclient/blocks/python/utils.py Thu Sep 02 15:02:14 2010 +0800
@@ -0,0 +1,424 @@
+#
+# Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of "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:
+# Various utility functions
+#
+
+import timeit
+import platform
+import logging
+import logging.handlers
+import os
+import sys
+import stat
+import shutil
+import atexit
+import urllib2
+import urlparse
+import fnmatch
+import tempfile
+import itertools
+
+from generalexceptions import GenericError
+
+URL_SCHEMES = ("http", "https", "ftp", "ftps", "file")
+
+loglevel = logging.DEBUG
+
+def platformIsWindows():
+ return platform.system() == "Windows"
+
+class StopWatch(object): # pragma: no cover
+ ''' Measure elapsed time '''
+ def __init__(self, start=True):
+ self.start_time = None
+ self.stopped = False
+ if start:
+ self.start()
+
+ def start(self):
+ self.stopped = False
+ self.start_time = timeit.default_timer()
+
+ def stop(self):
+ if not self.stopped:
+ self.stopped = self.elapsed()
+ return self.stopped
+
+ def elapsed(self):
+ if self.stopped:
+ return self.stopped
+
+ if self.start_time:
+ elapsed = timeit.default_timer() - self.start_time
+ else:
+ elapsed = None
+ return elapsed
+
+def getErrorFunction(errortext):
+ def errorFunction(*args, **kwargs):
+ exit("Error: %s" % errortext)
+ return errorFunction
+
+def getRealPath(origpath):
+ realpath = origpath
+ if platformIsWindows():
+ try:
+ import win32file
+ except ImportError: # pragma: no cover
+ logging.warning("Pywin32 extension not available. Subst support disabled.")
+ return realpath
+
+ (drive, relpath) = os.path.splitdrive(origpath)
+ dev = win32file.QueryDosDevice(drive)
+ if dev.startswith("\\??\\"):
+ dev = dev[4:-2]
+ realpath = os.path.join(dev, relpath[1:])
+ logging.debug("Directory '%s' is on substed drive %s => %s. Real path is %s", origpath, drive, dev, realpath)
+ return realpath
+
+def getMetaPath():
+ altPath = os.environ.get("BLOCKS_METADATA")
+ if altPath:
+ blocksPath = altPath
+ else:
+ homeEnv = "APPDATA" if platformIsWindows() else "HOME"
+ home = os.environ.get(homeEnv)
+ if home is None:
+ raise GenericError("Could not get home directory from environment variable %s.\n"
+ "Please define BLOCKS_METADATA environment variable to set blocks home dir." % homeEnv)
+ blocksPath = os.path.join(home, "Blocks" if platformIsWindows() else ".blocks")
+ blocksPath = os.path.normcase(blocksPath)
+ if not os.path.isdir(blocksPath):
+ os.mkdir(blocksPath) # pragma: no cover
+ return blocksPath
+
+def addSearchPath(path):
+ envPath = os.environ.get("PATH", "")
+ if path not in envPath:
+ os.environ["PATH"] = os.pathsep.join([path, envPath])
+
+def pathsUnique(path1, path2):
+ path1 = addPathSep(os.path.normcase(path1))
+ path2 = addPathSep(os.path.normcase(path2))
+ return not (path1.startswith(path2) or path2.startswith(path1))
+
+def pathInside(root, path, equalInside=True):
+ root = addPathSep(os.path.normcase(root))
+ path = addPathSep(os.path.normcase(path))
+ if not equalInside and path == root:
+ return False
+ return path.startswith(root)
+
+def removeStart(text, remove):
+ ''' Case-insensitive removing of text in start of string '''
+ removeCount = len(text) - len(text.lower().replace(remove.lower(), "", 1))
+ return text[removeCount:]
+
+def setReadOnly(path, read_only=True): # pragma: no cover
+ os.chmod(path, stat.S_IREAD if read_only else stat.S_IWRITE)
+
+def forceDelete(path): # pragma: no cover
+ ''' Deletes read-only files '''
+ os.chmod(path, stat.S_IWRITE)
+ os.remove(path)
+
+def __readOnlyDelete(func, path, exc): # pragma: no cover
+ os.chmod(path, stat.S_IWRITE)
+ func(path)
+
+def superDelete(path): # pragma: no cover
+ ''' Deletes both files and directories even if read-only '''
+ if os.path.isfile(path):
+ forceDelete(path)
+ elif os.path.isdir(path):
+ shutil.rmtree(path, onerror=__readOnlyDelete)
+
+DETAILED_LOG_FORMAT = '%(asctime)s.%(msecs)d - %(levelname)s: %(message)s'
+DETAILED_LOG_TIMEFORMAT = "%d.%m.%Y %H:%M:%S"
+DEFAULT_LOG_FORMAT = '%(levelname)s: %(message)s'
+
+def getConsoleLogFormat():
+ if loglevel <= logging.DEBUG:
+ return (DETAILED_LOG_FORMAT, DETAILED_LOG_TIMEFORMAT)
+ else:
+ return (DEFAULT_LOG_FORMAT, None)
+
+def setupLogging(version, verbose, path=None):
+ global loglevel
+
+ if not os.path.isabs(path):
+ path = os.path.join(getMetaPath(), path)
+
+ logging.DEBUG2 = logging.DEBUG - 1
+ logging.addLevelName(logging.DEBUG2, "DEBUG2")
+ verbosityToLoglevel = {-2: logging.CRITICAL,
+ -1: logging.ERROR,
+ 0: logging.WARNING,
+ 1: logging.INFO,
+ 2: logging.DEBUG,
+ 3: logging.DEBUG2}
+ minVerbosity = min(verbosityToLoglevel.keys())
+ maxVerbosity = max(verbosityToLoglevel.keys())
+ verbose = min(max(verbose, minVerbosity), maxVerbosity)
+ loglevel = verbosityToLoglevel[verbose]
+
+ logger = logging.getLogger()
+ logger.setLevel(logging.NOTSET)
+
+ console = logging.StreamHandler()
+ console.setLevel(loglevel)
+ formatter = logging.Formatter(*getConsoleLogFormat())
+ console.setFormatter(formatter)
+ logger.addHandler(console)
+
+ fileHandler = logging.handlers.RotatingFileHandler(path, maxBytes=500000, backupCount=1)
+ if __debug__:
+ fileHandler.setLevel(loglevel if loglevel < logging.DEBUG else logging.DEBUG)
+ else:
+ fileHandler.setLevel(loglevel)
+ formatter = logging.Formatter(DETAILED_LOG_FORMAT, DETAILED_LOG_TIMEFORMAT)
+ fileHandler.setFormatter(formatter)
+ logger.addHandler(fileHandler)
+
+ cpu_count = "Unknown"
+ try:
+ import multiprocessing
+ cpu_count = multiprocessing.cpu_count()
+ except ImportError: # pragma: no cover
+ pass
+
+ logging.debug("%s started (PID %s) [OS: %s | Python: %s | CPU: %s | CPU Count: %s]",
+ version,
+ os.getpid(),
+ platform.platform(),
+ platform.python_version(),
+ platform.processor(),
+ cpu_count)
+ stopwatch = StopWatch()
+
+ @atexit.register
+ def runatexit():
+ # Fix to make coverage work. logging was none
+ if logging: # pragma: no cover
+ logging.info("Stopped. Run time: %.3fs", stopwatch.stop())
+
+ return loglevel
+
+def addPathSep(path):
+ return addSuffix(path, os.sep)
+
+def addSuffix(text, suffix):
+ return text if text.endswith(suffix) else text + suffix
+
+def relativePath(path, root):
+ '''
+ Returns relative path if path is absolute
+ Keeps casing in the path, but on windows matching of path and root are done
+ in lower case
+ '''
+ if os.path.isabs(path):
+ root = os.path.abspath(root)
+ if pathInside(root, path):
+ path = os.path.normpath(path)
+ root = os.path.normpath(root)
+ root = addPathSep(root)
+ # On windows we don't care about path case
+ if platformIsWindows():
+ path = removeStart(path, root)
+ else:
+ path = path.replace(root, "", 1)
+ return path
+
+def removeFilesRecursive(path, glob):
+ for name in getFilesRecursive(path, glob):
+ os.remove(name)
+
+def getFilesRecursive(path, glob=None):
+ ''' Get list of all files recursively from a path '''
+ files = [os.path.join(root, name) for root, _, files in os.walk(path) for name in files]
+ if glob:
+ files = fnmatch.filter(files, glob)
+ return files
+
+def getFileLines(path):
+ lines = []
+ if path:
+ with open(path) as f:
+ lines = [line.strip() for line in f.readlines()]
+ return lines
+
+def warnIfFileNotFound(path):
+ if not os.path.isfile(path):
+ if os.path.isdir(path):
+ logging.warning("No such file: %s. Directory found instead.", path)
+ else:
+ logging.warning("No such file: %s", path)
+
+def createFile(path):
+ open(path, "a+").close()
+
+def createDir(path):
+ '''
+ Create directory if it doesn't exist.
+ Ignores errors.
+ '''
+ try:
+ os.makedirs(path)
+ except OSError:
+ pass
+
+def getInstallDir():
+ return os.path.normpath(os.path.join(os.path.dirname(__file__), ".."))
+
+def copyFileData(src, dst, size=None, blocksize=32*1024):
+ ''' Copy data from source file to destination file '''
+ bytesread = 0
+ while size is None or bytesread < size:
+ if size and (bytesread + blocksize) >= size:
+ blocksize = size - bytesread
+ buf = src.read(blocksize)
+ bytesread += blocksize
+ if not buf:
+ break
+ dst.write(buf)
+
+def fileobjsEqual(fobj1, fobj2):
+ for line in fobj1:
+ if line != fobj2.readline():
+ return False
+ return True
+
+def getUtilDir():
+ binDir = os.path.join(getInstallDir(), "utils")
+ binDir = binDir.replace("\\", "/")
+ return binDir
+
+def initSearchPath():
+ addSearchPath(getUtilDir())
+
+def urlretrieve(url, path):
+ urlFile = openUrl(url)
+ try:
+ with open(path, "wb") as f:
+ copyFileData(urlFile, f)
+ finally:
+ urlFile.close()
+
+def openUrl(url, timeout=10):
+ ''' If URL cannot be opened raises IOError '''
+ errorText = "Problem on fetching '%s'" % url
+ try:
+ scheme = validateURL(url)
+ except ValueError, ex:
+ raise IOError("%s: %s" % (errorText, ex))
+
+ try:
+ urlFile = urllib2.urlopen(url, timeout=timeout)
+ except IOError, ex:
+ if hasattr(ex, "reason"):
+ problem = "Local file cannot be found" if scheme == "file" else "Server cannot be reached"
+ exc = IOError("%s: %s.\nReason: %s" % (errorText, problem, ex.reason))
+ if scheme == "file":
+ exc.errno = 404
+ elif hasattr(ex, "code"):
+ exc = IOError("%s: %s" % (errorText, ex))
+ exc.errno = ex.code
+ raise exc
+
+ return urlFile
+
+def validateURL(url):
+ ''' Raises ValueError exception if invalid URL '''
+ scheme = urlparse.urlparse(url).scheme
+ if scheme not in URL_SCHEMES:
+ raise ValueError("Invalid URL '%s' with scheme '%s': Supported URL schemes: %s" % (url, scheme, ", ".join(URL_SCHEMES)))
+ return scheme
+
+def error(text, critical=False, noOutput=False, retCode=1):
+ if critical:
+ logging.error(text, exc_info=True) # pragma: no cover
+ else:
+ logging.debug(text, exc_info=True)
+ if loglevel == logging.DEBUG or critical:
+ sys.exit(retCode) # pragma: no cover
+ else:
+ if not noOutput:
+ print >> sys.stderr, text
+ sys.exit(retCode)
+
+def getVersion(infoModule):
+ info = __import__(infoModule)
+ if info.VERSION_PRE_RELEASE > 0:
+ pre_release = info.VERSION_PRE_RELEASE_ID + str(info.VERSION_PRE_RELEASE)
+ else:
+ pre_release = "" # pragma: no cover
+ return "%%prog %d.%d.%d%s (%s)" % (info.VERSION_MAJOR,
+ info.VERSION_MINOR,
+ info.VERSION_REVISION,
+ pre_release,
+ info.VERSION_DATE or "dev")
+
+def atomicFileCreate(path, data):
+ tmpfile = tempfile.NamedTemporaryFile(bufsize=0, delete=False)
+ try:
+ tmpfile.write(data)
+ tmpfile.flush()
+ os.fsync(tmpfile.fileno())
+ tmpfile.close()
+ os.rename(tmpfile.name, path)
+ except Exception: # cleanup
+ tmpfile.close()
+ os.remove(tmpfile.name)
+ raise
+
+def uniqueName(prefix, usedNames):
+ for idnum in itertools.count(1):
+ name = "%s%d" % (prefix, idnum)
+ if name not in usedNames:
+ break
+ return name
+
+def isFile(name, ext):
+ ''' Checks if there is a file having extension ext with given name '''
+ return name.lower().endswith(ext) and os.path.isfile(name)
+
+def argsToStr(*args):
+ ''' Takes at least one string or iterable containing strings and quotes all that have spaces and returns string '''
+ argList = listify(*args)
+ for i, arg in enumerate(argList):
+ if " " in arg:
+ argList[i] = '"%s"' % arg
+ return " ".join(argList)
+
+def listify(*args):
+ retList = []
+ for arg in args:
+ if hasattr(arg, "__iter__"):
+ retList.extend(list(arg))
+ else:
+ retList.append(arg)
+ return retList
+
+def toBoolean(var):
+ if isinstance(var, bool):
+ return var
+ return {"yes": True, "true": True, "1": True, "enable": True,
+ "no": False, "false": False, "0": False, "disable": False}.get(var.lower() if var else None)
+
+def test():
+ print relativePath(r"c:\users\work\vc\blocks\blocks\python\data.py", ".")
+
+if __name__ == "__main__":
+ test()
\ No newline at end of file