summaryrefslogtreecommitdiffstats
path: root/WebKitTools/Scripts/webkitpy/common/system
diff options
context:
space:
mode:
Diffstat (limited to 'WebKitTools/Scripts/webkitpy/common/system')
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/__init__.py1
-rwxr-xr-xWebKitTools/Scripts/webkitpy/common/system/autoinstall.py517
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/deprecated_logging.py91
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/deprecated_logging_unittest.py60
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/executive.py399
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/executive_mock.py59
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/executive_unittest.py151
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/file_lock.py83
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/file_lock_unittest.py61
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/filesystem.py117
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/filesystem_mock.py80
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/filesystem_unittest.py157
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/fileutils.py33
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/logtesting.py258
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/logutils.py207
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/logutils_unittest.py142
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/ospath.py83
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/ospath_unittest.py62
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/outputcapture.py86
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/path.py138
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/path_unittest.py105
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/user.py143
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/user_unittest.py109
23 files changed, 0 insertions, 3142 deletions
diff --git a/WebKitTools/Scripts/webkitpy/common/system/__init__.py b/WebKitTools/Scripts/webkitpy/common/system/__init__.py
deleted file mode 100644
index ef65bee..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# Required for Python to search this directory for module files
diff --git a/WebKitTools/Scripts/webkitpy/common/system/autoinstall.py b/WebKitTools/Scripts/webkitpy/common/system/autoinstall.py
deleted file mode 100755
index 9adab29..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/autoinstall.py
+++ /dev/null
@@ -1,517 +0,0 @@
-# Copyright (c) 2009, Daniel Krech All rights reserved.
-# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org)
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#
-# * Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-#
-# * Neither the name of the Daniel Krech nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Support for automatically downloading Python packages from an URL."""
-
-
-from __future__ import with_statement
-
-import codecs
-import logging
-import new
-import os
-import shutil
-import sys
-import tarfile
-import tempfile
-import urllib
-import urlparse
-import zipfile
-import zipimport
-
-_log = logging.getLogger(__name__)
-
-
-class AutoInstaller(object):
-
- """Supports automatically installing Python packages from an URL.
-
- Supports uncompressed files, .tar.gz, and .zip formats.
-
- Basic usage:
-
- installer = AutoInstaller()
-
- installer.install(url="http://pypi.python.org/packages/source/p/pep8/pep8-0.5.0.tar.gz#md5=512a818af9979290cd619cce8e9c2e2b",
- url_subpath="pep8-0.5.0/pep8.py")
- installer.install(url="http://pypi.python.org/packages/source/m/mechanize/mechanize-0.1.11.zip",
- url_subpath="mechanize")
-
- """
-
- def __init__(self, append_to_search_path=False, make_package=True,
- target_dir=None, temp_dir=None):
- """Create an AutoInstaller instance, and set up the target directory.
-
- Args:
- append_to_search_path: A boolean value of whether to append the
- target directory to the sys.path search path.
- make_package: A boolean value of whether to make the target
- directory a package. This adds an __init__.py file
- to the target directory -- allowing packages and
- modules within the target directory to be imported
- explicitly using dotted module names.
- target_dir: The directory path to which packages should be installed.
- Defaults to a subdirectory of the folder containing
- this module called "autoinstalled".
- temp_dir: The directory path to use for any temporary files
- generated while downloading, unzipping, and extracting
- packages to install. Defaults to a standard temporary
- location generated by the tempfile module. This
- parameter should normally be used only for development
- testing.
-
- """
- if target_dir is None:
- this_dir = os.path.dirname(__file__)
- target_dir = os.path.join(this_dir, "autoinstalled")
-
- # Ensure that the target directory exists.
- self._set_up_target_dir(target_dir, append_to_search_path, make_package)
-
- self._target_dir = target_dir
- self._temp_dir = temp_dir
-
- def _log_transfer(self, message, source, target, log_method=None):
- """Log a debug message that involves a source and target."""
- if log_method is None:
- log_method = _log.debug
-
- log_method("%s" % message)
- log_method(' From: "%s"' % source)
- log_method(' To: "%s"' % target)
-
- def _create_directory(self, path, name=None):
- """Create a directory."""
- log = _log.debug
-
- name = name + " " if name is not None else ""
- log('Creating %sdirectory...' % name)
- log(' "%s"' % path)
-
- os.makedirs(path)
-
- def _write_file(self, path, text, encoding):
- """Create a file at the given path with given text.
-
- This method overwrites any existing file.
-
- """
- _log.debug("Creating file...")
- _log.debug(' "%s"' % path)
- with codecs.open(path, "w", encoding) as file:
- file.write(text)
-
- def _set_up_target_dir(self, target_dir, append_to_search_path,
- make_package):
- """Set up a target directory.
-
- Args:
- target_dir: The path to the target directory to set up.
- append_to_search_path: A boolean value of whether to append the
- target directory to the sys.path search path.
- make_package: A boolean value of whether to make the target
- directory a package. This adds an __init__.py file
- to the target directory -- allowing packages and
- modules within the target directory to be imported
- explicitly using dotted module names.
-
- """
- if not os.path.exists(target_dir):
- self._create_directory(target_dir, "autoinstall target")
-
- if append_to_search_path:
- sys.path.append(target_dir)
-
- if make_package:
- init_path = os.path.join(target_dir, "__init__.py")
- if not os.path.exists(init_path):
- text = ("# This file is required for Python to search this "
- "directory for modules.\n")
- self._write_file(init_path, text, "ascii")
-
- def _create_scratch_directory_inner(self, prefix):
- """Create a scratch directory without exception handling.
-
- Creates a scratch directory inside the AutoInstaller temp
- directory self._temp_dir, or inside a platform-dependent temp
- directory if self._temp_dir is None. Returns the path to the
- created scratch directory.
-
- Raises:
- OSError: [Errno 2] if the containing temp directory self._temp_dir
- is not None and does not exist.
-
- """
- # The tempfile.mkdtemp() method function requires that the
- # directory corresponding to the "dir" parameter already exist
- # if it is not None.
- scratch_dir = tempfile.mkdtemp(prefix=prefix, dir=self._temp_dir)
- return scratch_dir
-
- def _create_scratch_directory(self, target_name):
- """Create a temporary scratch directory, and return its path.
-
- The scratch directory is generated inside the temp directory
- of this AutoInstaller instance. This method also creates the
- temp directory if it does not already exist.
-
- """
- prefix = target_name + "_"
- try:
- scratch_dir = self._create_scratch_directory_inner(prefix)
- except OSError:
- # Handle case of containing temp directory not existing--
- # OSError: [Errno 2] No such file or directory:...
- temp_dir = self._temp_dir
- if temp_dir is None or os.path.exists(temp_dir):
- raise
- # Else try again after creating the temp directory.
- self._create_directory(temp_dir, "autoinstall temp")
- scratch_dir = self._create_scratch_directory_inner(prefix)
-
- return scratch_dir
-
- def _url_downloaded_path(self, target_name):
- """Return the path to the file containing the URL downloaded."""
- filename = ".%s.url" % target_name
- path = os.path.join(self._target_dir, filename)
- return path
-
- def _is_downloaded(self, target_name, url):
- """Return whether a package version has been downloaded."""
- version_path = self._url_downloaded_path(target_name)
-
- _log.debug('Checking %s URL downloaded...' % target_name)
- _log.debug(' "%s"' % version_path)
-
- if not os.path.exists(version_path):
- # Then no package version has been downloaded.
- _log.debug("No URL file found.")
- return False
-
- with codecs.open(version_path, "r", "utf-8") as file:
- version = file.read()
-
- return version.strip() == url.strip()
-
- def _record_url_downloaded(self, target_name, url):
- """Record the URL downloaded to a file."""
- version_path = self._url_downloaded_path(target_name)
- _log.debug("Recording URL downloaded...")
- _log.debug(' URL: "%s"' % url)
- _log.debug(' To: "%s"' % version_path)
-
- self._write_file(version_path, url, "utf-8")
-
- def _extract_targz(self, path, scratch_dir):
- # tarfile.extractall() extracts to a path without the
- # trailing ".tar.gz".
- target_basename = os.path.basename(path[:-len(".tar.gz")])
- target_path = os.path.join(scratch_dir, target_basename)
-
- self._log_transfer("Starting gunzip/extract...", path, target_path)
-
- try:
- tar_file = tarfile.open(path)
- except tarfile.ReadError, err:
- # Append existing Error message to new Error.
- message = ("Could not open tar file: %s\n"
- " The file probably does not have the correct format.\n"
- " --> Inner message: %s"
- % (path, err))
- raise Exception(message)
-
- try:
- # This is helpful for debugging purposes.
- _log.debug("Listing tar file contents...")
- for name in tar_file.getnames():
- _log.debug(' * "%s"' % name)
- _log.debug("Extracting gzipped tar file...")
- tar_file.extractall(target_path)
- finally:
- tar_file.close()
-
- return target_path
-
- # This is a replacement for ZipFile.extractall(), which is
- # available in Python 2.6 but not in earlier versions.
- def _extract_all(self, zip_file, target_dir):
- self._log_transfer("Extracting zip file...", zip_file, target_dir)
-
- # This is helpful for debugging purposes.
- _log.debug("Listing zip file contents...")
- for name in zip_file.namelist():
- _log.debug(' * "%s"' % name)
-
- for name in zip_file.namelist():
- path = os.path.join(target_dir, name)
- self._log_transfer("Extracting...", name, path)
-
- if not os.path.basename(path):
- # Then the path ends in a slash, so it is a directory.
- self._create_directory(path)
- continue
- # Otherwise, it is a file.
-
- try:
- # We open this file w/o encoding, as we're reading/writing
- # the raw byte-stream from the zip file.
- outfile = open(path, 'wb')
- except IOError, err:
- # Not all zip files seem to list the directories explicitly,
- # so try again after creating the containing directory.
- _log.debug("Got IOError: retrying after creating directory...")
- dir = os.path.dirname(path)
- self._create_directory(dir)
- outfile = open(path, 'wb')
-
- try:
- outfile.write(zip_file.read(name))
- finally:
- outfile.close()
-
- def _unzip(self, path, scratch_dir):
- # zipfile.extractall() extracts to a path without the
- # trailing ".zip".
- target_basename = os.path.basename(path[:-len(".zip")])
- target_path = os.path.join(scratch_dir, target_basename)
-
- self._log_transfer("Starting unzip...", path, target_path)
-
- try:
- zip_file = zipfile.ZipFile(path, "r")
- except zipfile.BadZipfile, err:
- message = ("Could not open zip file: %s\n"
- " --> Inner message: %s"
- % (path, err))
- raise Exception(message)
-
- try:
- self._extract_all(zip_file, scratch_dir)
- finally:
- zip_file.close()
-
- return target_path
-
- def _prepare_package(self, path, scratch_dir):
- """Prepare a package for use, if necessary, and return the new path.
-
- For example, this method unzips zipped files and extracts
- tar files.
-
- Args:
- path: The path to the downloaded URL contents.
- scratch_dir: The scratch directory. Note that the scratch
- directory contains the file designated by the
- path parameter.
-
- """
- # FIXME: Add other natural extensions.
- if path.endswith(".zip"):
- new_path = self._unzip(path, scratch_dir)
- elif path.endswith(".tar.gz"):
- new_path = self._extract_targz(path, scratch_dir)
- else:
- # No preparation is needed.
- new_path = path
-
- return new_path
-
- def _download_to_stream(self, url, stream):
- """Download an URL to a stream, and return the number of bytes."""
- try:
- netstream = urllib.urlopen(url)
- except IOError, err:
- # Append existing Error message to new Error.
- message = ('Could not download Python modules from URL "%s".\n'
- " Make sure you are connected to the internet.\n"
- " You must be connected to the internet when "
- "downloading needed modules for the first time.\n"
- " --> Inner message: %s"
- % (url, err))
- raise IOError(message)
- code = 200
- if hasattr(netstream, "getcode"):
- code = netstream.getcode()
- if not 200 <= code < 300:
- raise ValueError("HTTP Error code %s" % code)
-
- BUFSIZE = 2**13 # 8KB
- bytes = 0
- while True:
- data = netstream.read(BUFSIZE)
- if not data:
- break
- stream.write(data)
- bytes += len(data)
- netstream.close()
- return bytes
-
- def _download(self, url, scratch_dir):
- """Download URL contents, and return the download path."""
- url_path = urlparse.urlsplit(url)[2]
- url_path = os.path.normpath(url_path) # Removes trailing slash.
- target_filename = os.path.basename(url_path)
- target_path = os.path.join(scratch_dir, target_filename)
-
- self._log_transfer("Starting download...", url, target_path)
-
- with open(target_path, "wb") as stream:
- bytes = self._download_to_stream(url, stream)
-
- _log.debug("Downloaded %s bytes." % bytes)
-
- return target_path
-
- def _install(self, scratch_dir, package_name, target_path, url,
- url_subpath):
- """Install a python package from an URL.
-
- This internal method overwrites the target path if the target
- path already exists.
-
- """
- path = self._download(url=url, scratch_dir=scratch_dir)
- path = self._prepare_package(path, scratch_dir)
-
- if url_subpath is None:
- source_path = path
- else:
- source_path = os.path.join(path, url_subpath)
-
- if os.path.exists(target_path):
- _log.debug('Refreshing install: deleting "%s".' % target_path)
- if os.path.isdir(target_path):
- shutil.rmtree(target_path)
- else:
- os.remove(target_path)
-
- self._log_transfer("Moving files into place...", source_path, target_path)
-
- # The shutil.move() command creates intermediate directories if they
- # do not exist, but we do not rely on this behavior since we
- # need to create the __init__.py file anyway.
- shutil.move(source_path, target_path)
-
- self._record_url_downloaded(package_name, url)
-
- def install(self, url, should_refresh=False, target_name=None,
- url_subpath=None):
- """Install a python package from an URL.
-
- Args:
- url: The URL from which to download the package.
-
- Optional Args:
- should_refresh: A boolean value of whether the package should be
- downloaded again if the package is already present.
- target_name: The name of the folder or file in the autoinstaller
- target directory at which the package should be
- installed. Defaults to the base name of the
- URL sub-path. This parameter must be provided if
- the URL sub-path is not specified.
- url_subpath: The relative path of the URL directory that should
- be installed. Defaults to the full directory, or
- the entire URL contents.
-
- """
- if target_name is None:
- if not url_subpath:
- raise ValueError('The "target_name" parameter must be '
- 'provided if the "url_subpath" parameter '
- "is not provided.")
- # Remove any trailing slashes.
- url_subpath = os.path.normpath(url_subpath)
- target_name = os.path.basename(url_subpath)
-
- target_path = os.path.join(self._target_dir, target_name)
- if not should_refresh and self._is_downloaded(target_name, url):
- _log.debug('URL for %s already downloaded. Skipping...'
- % target_name)
- _log.debug(' "%s"' % url)
- return
-
- self._log_transfer("Auto-installing package: %s" % target_name,
- url, target_path, log_method=_log.info)
-
- # The scratch directory is where we will download and prepare
- # files specific to this install until they are ready to move
- # into place.
- scratch_dir = self._create_scratch_directory(target_name)
-
- try:
- self._install(package_name=target_name,
- target_path=target_path,
- scratch_dir=scratch_dir,
- url=url,
- url_subpath=url_subpath)
- except Exception, err:
- # Append existing Error message to new Error.
- message = ("Error auto-installing the %s package to:\n"
- ' "%s"\n'
- " --> Inner message: %s"
- % (target_name, target_path, err))
- raise Exception(message)
- finally:
- _log.debug('Cleaning up: deleting "%s".' % scratch_dir)
- shutil.rmtree(scratch_dir)
- _log.debug('Auto-installed %s to:' % target_name)
- _log.debug(' "%s"' % target_path)
-
-
-if __name__=="__main__":
-
- # Configure the autoinstall logger to log DEBUG messages for
- # development testing purposes.
- console = logging.StreamHandler()
-
- formatter = logging.Formatter('%(name)s: %(levelname)-8s %(message)s')
- console.setFormatter(formatter)
- _log.addHandler(console)
- _log.setLevel(logging.DEBUG)
-
- # Use a more visible temp directory for debug purposes.
- this_dir = os.path.dirname(__file__)
- target_dir = os.path.join(this_dir, "autoinstalled")
- temp_dir = os.path.join(target_dir, "Temp")
-
- installer = AutoInstaller(target_dir=target_dir,
- temp_dir=temp_dir)
-
- installer.install(should_refresh=False,
- target_name="pep8.py",
- url="http://pypi.python.org/packages/source/p/pep8/pep8-0.5.0.tar.gz#md5=512a818af9979290cd619cce8e9c2e2b",
- url_subpath="pep8-0.5.0/pep8.py")
- installer.install(should_refresh=False,
- target_name="mechanize",
- url="http://pypi.python.org/packages/source/m/mechanize/mechanize-0.1.11.zip",
- url_subpath="mechanize")
-
diff --git a/WebKitTools/Scripts/webkitpy/common/system/deprecated_logging.py b/WebKitTools/Scripts/webkitpy/common/system/deprecated_logging.py
deleted file mode 100644
index 9e6b529..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/deprecated_logging.py
+++ /dev/null
@@ -1,91 +0,0 @@
-# Copyright (c) 2009, Google Inc. All rights reserved.
-# Copyright (c) 2009 Apple Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# WebKit's Python module for logging
-# This module is now deprecated in favor of python's built-in logging.py.
-
-import codecs
-import os
-import sys
-
-
-def log(string):
- print >> sys.stderr, string
-
-
-def error(string):
- log("ERROR: %s" % string)
- exit(1)
-
-
-# Simple class to split output between multiple destinations
-class tee:
- def __init__(self, *files):
- self.files = files
-
- # Callers should pass an already encoded string for writing.
- def write(self, bytes):
- for file in self.files:
- file.write(bytes)
-
-
-class OutputTee:
- def __init__(self):
- self._original_stdout = None
- self._original_stderr = None
- self._files_for_output = []
-
- def add_log(self, path):
- log_file = self._open_log_file(path)
- self._files_for_output.append(log_file)
- self._tee_outputs_to_files(self._files_for_output)
- return log_file
-
- def remove_log(self, log_file):
- self._files_for_output.remove(log_file)
- self._tee_outputs_to_files(self._files_for_output)
- log_file.close()
-
- @staticmethod
- def _open_log_file(log_path):
- (log_directory, log_name) = os.path.split(log_path)
- if log_directory and not os.path.exists(log_directory):
- os.makedirs(log_directory)
- return codecs.open(log_path, "a+", "utf-8")
-
- def _tee_outputs_to_files(self, files):
- if not self._original_stdout:
- self._original_stdout = sys.stdout
- self._original_stderr = sys.stderr
- if files and len(files):
- sys.stdout = tee(self._original_stdout, *files)
- sys.stderr = tee(self._original_stderr, *files)
- else:
- sys.stdout = self._original_stdout
- sys.stderr = self._original_stderr
diff --git a/WebKitTools/Scripts/webkitpy/common/system/deprecated_logging_unittest.py b/WebKitTools/Scripts/webkitpy/common/system/deprecated_logging_unittest.py
deleted file mode 100644
index 3778162..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/deprecated_logging_unittest.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright (C) 2009 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import os
-import StringIO
-import tempfile
-import unittest
-
-from webkitpy.common.system.executive import ScriptError
-from webkitpy.common.system.deprecated_logging import *
-
-class LoggingTest(unittest.TestCase):
-
- def assert_log_equals(self, log_input, expected_output):
- original_stderr = sys.stderr
- test_stderr = StringIO.StringIO()
- sys.stderr = test_stderr
-
- try:
- log(log_input)
- actual_output = test_stderr.getvalue()
- finally:
- sys.stderr = original_stderr
-
- self.assertEquals(actual_output, expected_output, "log(\"%s\") expected: %s actual: %s" % (log_input, expected_output, actual_output))
-
- def test_log(self):
- self.assert_log_equals("test", "test\n")
-
- # Test that log() does not throw an exception when passed an object instead of a string.
- self.assert_log_equals(ScriptError(message="ScriptError"), "ScriptError\n")
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/WebKitTools/Scripts/webkitpy/common/system/executive.py b/WebKitTools/Scripts/webkitpy/common/system/executive.py
deleted file mode 100644
index 85a683a..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/executive.py
+++ /dev/null
@@ -1,399 +0,0 @@
-# Copyright (c) 2009, Google Inc. All rights reserved.
-# Copyright (c) 2009 Apple Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-try:
- # This API exists only in Python 2.6 and higher. :(
- import multiprocessing
-except ImportError:
- multiprocessing = None
-
-import ctypes
-import errno
-import logging
-import os
-import platform
-import StringIO
-import signal
-import subprocess
-import sys
-import time
-
-from webkitpy.common.system.deprecated_logging import tee
-from webkitpy.python24 import versioning
-
-
-_log = logging.getLogger("webkitpy.common.system")
-
-
-class ScriptError(Exception):
-
- def __init__(self,
- message=None,
- script_args=None,
- exit_code=None,
- output=None,
- cwd=None):
- if not message:
- message = 'Failed to run "%s"' % script_args
- if exit_code:
- message += " exit_code: %d" % exit_code
- if cwd:
- message += " cwd: %s" % cwd
-
- Exception.__init__(self, message)
- self.script_args = script_args # 'args' is already used by Exception
- self.exit_code = exit_code
- self.output = output
- self.cwd = cwd
-
- def message_with_output(self, output_limit=500):
- if self.output:
- if output_limit and len(self.output) > output_limit:
- return u"%s\nLast %s characters of output:\n%s" % \
- (self, output_limit, self.output[-output_limit:])
- return u"%s\n%s" % (self, self.output)
- return unicode(self)
-
- def command_name(self):
- command_path = self.script_args
- if type(command_path) is list:
- command_path = command_path[0]
- return os.path.basename(command_path)
-
-
-def run_command(*args, **kwargs):
- # FIXME: This should not be a global static.
- # New code should use Executive.run_command directly instead
- return Executive().run_command(*args, **kwargs)
-
-
-class Executive(object):
-
- def _should_close_fds(self):
- # We need to pass close_fds=True to work around Python bug #2320
- # (otherwise we can hang when we kill DumpRenderTree when we are running
- # multiple threads). See http://bugs.python.org/issue2320 .
- # Note that close_fds isn't supported on Windows, but this bug only
- # shows up on Mac and Linux.
- return sys.platform not in ('win32', 'cygwin')
-
- def _run_command_with_teed_output(self, args, teed_output):
- args = map(unicode, args) # Popen will throw an exception if args are non-strings (like int())
- args = map(self._encode_argument_if_needed, args)
-
- child_process = subprocess.Popen(args,
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT,
- close_fds=self._should_close_fds())
-
- # Use our own custom wait loop because Popen ignores a tee'd
- # stderr/stdout.
- # FIXME: This could be improved not to flatten output to stdout.
- while True:
- output_line = child_process.stdout.readline()
- if output_line == "" and child_process.poll() != None:
- # poll() is not threadsafe and can throw OSError due to:
- # http://bugs.python.org/issue1731717
- return child_process.poll()
- # We assume that the child process wrote to us in utf-8,
- # so no re-encoding is necessary before writing here.
- teed_output.write(output_line)
-
- # FIXME: Remove this deprecated method and move callers to run_command.
- # FIXME: This method is a hack to allow running command which both
- # capture their output and print out to stdin. Useful for things
- # like "build-webkit" where we want to display to the user that we're building
- # but still have the output to stuff into a log file.
- def run_and_throw_if_fail(self, args, quiet=False, decode_output=True):
- # Cache the child's output locally so it can be used for error reports.
- child_out_file = StringIO.StringIO()
- tee_stdout = sys.stdout
- if quiet:
- dev_null = open(os.devnull, "w") # FIXME: Does this need an encoding?
- tee_stdout = dev_null
- child_stdout = tee(child_out_file, tee_stdout)
- exit_code = self._run_command_with_teed_output(args, child_stdout)
- if quiet:
- dev_null.close()
-
- child_output = child_out_file.getvalue()
- child_out_file.close()
-
- if decode_output:
- child_output = child_output.decode(self._child_process_encoding())
-
- if exit_code:
- raise ScriptError(script_args=args,
- exit_code=exit_code,
- output=child_output)
- return child_output
-
- def cpu_count(self):
- if multiprocessing:
- return multiprocessing.cpu_count()
- # Darn. We don't have the multiprocessing package.
- system_name = platform.system()
- if system_name == "Darwin":
- return int(self.run_command(["sysctl", "-n", "hw.ncpu"]))
- elif system_name == "Windows":
- return int(os.environ.get('NUMBER_OF_PROCESSORS', 1))
- elif system_name == "Linux":
- num_cores = os.sysconf("SC_NPROCESSORS_ONLN")
- if isinstance(num_cores, int) and num_cores > 0:
- return num_cores
- # This quantity is a lie but probably a reasonable guess for modern
- # machines.
- return 2
-
- def kill_process(self, pid):
- """Attempts to kill the given pid.
- Will fail silently if pid does not exist or insufficient permisssions."""
- if sys.platform == "win32":
- # We only use taskkill.exe on windows (not cygwin) because subprocess.pid
- # is a CYGWIN pid and taskkill.exe expects a windows pid.
- # Thankfully os.kill on CYGWIN handles either pid type.
- command = ["taskkill.exe", "/f", "/pid", pid]
- # taskkill will exit 128 if the process is not found. We should log.
- self.run_command(command, error_handler=self.ignore_error)
- return
-
- # According to http://docs.python.org/library/os.html
- # os.kill isn't available on Windows. python 2.5.5 os.kill appears
- # to work in cygwin, however it occasionally raises EAGAIN.
- retries_left = 10 if sys.platform == "cygwin" else 1
- while retries_left > 0:
- try:
- retries_left -= 1
- os.kill(pid, signal.SIGKILL)
- except OSError, e:
- if e.errno == errno.EAGAIN:
- if retries_left <= 0:
- _log.warn("Failed to kill pid %s. Too many EAGAIN errors." % pid)
- continue
- if e.errno == errno.ESRCH: # The process does not exist.
- _log.warn("Called kill_process with a non-existant pid %s" % pid)
- return
- raise
-
- def _win32_check_running_pid(self, pid):
-
- class PROCESSENTRY32(ctypes.Structure):
- _fields_ = [("dwSize", ctypes.c_ulong),
- ("cntUsage", ctypes.c_ulong),
- ("th32ProcessID", ctypes.c_ulong),
- ("th32DefaultHeapID", ctypes.c_ulong),
- ("th32ModuleID", ctypes.c_ulong),
- ("cntThreads", ctypes.c_ulong),
- ("th32ParentProcessID", ctypes.c_ulong),
- ("pcPriClassBase", ctypes.c_ulong),
- ("dwFlags", ctypes.c_ulong),
- ("szExeFile", ctypes.c_char * 260)]
-
- CreateToolhelp32Snapshot = ctypes.windll.kernel32.CreateToolhelp32Snapshot
- Process32First = ctypes.windll.kernel32.Process32First
- Process32Next = ctypes.windll.kernel32.Process32Next
- CloseHandle = ctypes.windll.kernel32.CloseHandle
- TH32CS_SNAPPROCESS = 0x00000002 # win32 magic number
- hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
- pe32 = PROCESSENTRY32()
- pe32.dwSize = ctypes.sizeof(PROCESSENTRY32)
- result = False
- if not Process32First(hProcessSnap, ctypes.byref(pe32)):
- _log.debug("Failed getting first process.")
- CloseHandle(hProcessSnap)
- return result
- while True:
- if pe32.th32ProcessID == pid:
- result = True
- break
- if not Process32Next(hProcessSnap, ctypes.byref(pe32)):
- break
- CloseHandle(hProcessSnap)
- return result
-
- def check_running_pid(self, pid):
- """Return True if pid is alive, otherwise return False."""
- if sys.platform in ('darwin', 'linux2', 'cygwin'):
- try:
- os.kill(pid, 0)
- return True
- except OSError:
- return False
- elif sys.platform == 'win32':
- return self._win32_check_running_pid(pid)
-
- assert(False)
-
- def _windows_image_name(self, process_name):
- name, extension = os.path.splitext(process_name)
- if not extension:
- # taskkill expects processes to end in .exe
- # If necessary we could add a flag to disable appending .exe.
- process_name = "%s.exe" % name
- return process_name
-
- def kill_all(self, process_name):
- """Attempts to kill processes matching process_name.
- Will fail silently if no process are found."""
- if sys.platform in ("win32", "cygwin"):
- image_name = self._windows_image_name(process_name)
- command = ["taskkill.exe", "/f", "/im", image_name]
- # taskkill will exit 128 if the process is not found. We should log.
- self.run_command(command, error_handler=self.ignore_error)
- return
-
- # FIXME: This is inconsistent that kill_all uses TERM and kill_process
- # uses KILL. Windows is always using /f (which seems like -KILL).
- # We should pick one mode, or add support for switching between them.
- # Note: Mac OS X 10.6 requires -SIGNALNAME before -u USER
- command = ["killall", "-TERM", "-u", os.getenv("USER"), process_name]
- # killall returns 1 if no process can be found and 2 on command error.
- # FIXME: We should pass a custom error_handler to allow only exit_code 1.
- # We should log in exit_code == 1
- self.run_command(command, error_handler=self.ignore_error)
-
- # Error handlers do not need to be static methods once all callers are
- # updated to use an Executive object.
-
- @staticmethod
- def default_error_handler(error):
- raise error
-
- @staticmethod
- def ignore_error(error):
- pass
-
- def _compute_stdin(self, input):
- """Returns (stdin, string_to_communicate)"""
- # FIXME: We should be returning /dev/null for stdin
- # or closing stdin after process creation to prevent
- # child processes from getting input from the user.
- if not input:
- return (None, None)
- if hasattr(input, "read"): # Check if the input is a file.
- return (input, None) # Assume the file is in the right encoding.
-
- # Popen in Python 2.5 and before does not automatically encode unicode objects.
- # http://bugs.python.org/issue5290
- # See https://bugs.webkit.org/show_bug.cgi?id=37528
- # for an example of a regresion caused by passing a unicode string directly.
- # FIXME: We may need to encode differently on different platforms.
- if isinstance(input, unicode):
- input = input.encode(self._child_process_encoding())
- return (subprocess.PIPE, input)
-
- def _command_for_printing(self, args):
- """Returns a print-ready string representing command args.
- The string should be copy/paste ready for execution in a shell."""
- escaped_args = []
- for arg in args:
- if isinstance(arg, unicode):
- # Escape any non-ascii characters for easy copy/paste
- arg = arg.encode("unicode_escape")
- # FIXME: Do we need to fix quotes here?
- escaped_args.append(arg)
- return " ".join(escaped_args)
-
- # FIXME: run_and_throw_if_fail should be merged into this method.
- def run_command(self,
- args,
- cwd=None,
- input=None,
- error_handler=None,
- return_exit_code=False,
- return_stderr=True,
- decode_output=True):
- """Popen wrapper for convenience and to work around python bugs."""
- assert(isinstance(args, list) or isinstance(args, tuple))
- start_time = time.time()
- args = map(unicode, args) # Popen will throw an exception if args are non-strings (like int())
- args = map(self._encode_argument_if_needed, args)
-
- stdin, string_to_communicate = self._compute_stdin(input)
- stderr = subprocess.STDOUT if return_stderr else None
-
- process = subprocess.Popen(args,
- stdin=stdin,
- stdout=subprocess.PIPE,
- stderr=stderr,
- cwd=cwd,
- close_fds=self._should_close_fds())
- output = process.communicate(string_to_communicate)[0]
-
- # run_command automatically decodes to unicode() unless explicitly told not to.
- if decode_output:
- output = output.decode(self._child_process_encoding())
-
- # wait() is not threadsafe and can throw OSError due to:
- # http://bugs.python.org/issue1731717
- exit_code = process.wait()
-
- _log.debug('"%s" took %.2fs' % (self._command_for_printing(args), time.time() - start_time))
-
- if return_exit_code:
- return exit_code
-
- if exit_code:
- script_error = ScriptError(script_args=args,
- exit_code=exit_code,
- output=output,
- cwd=cwd)
- (error_handler or self.default_error_handler)(script_error)
- return output
-
- def _child_process_encoding(self):
- # Win32 Python 2.x uses CreateProcessA rather than CreateProcessW
- # to launch subprocesses, so we have to encode arguments using the
- # current code page.
- if sys.platform == 'win32' and versioning.compare_version(sys, '3.0')[0] < 0:
- return 'mbcs'
- # All other platforms use UTF-8.
- # FIXME: Using UTF-8 on Cygwin will confuse Windows-native commands
- # which will expect arguments to be encoded using the current code
- # page.
- return 'utf-8'
-
- def _should_encode_child_process_arguments(self):
- # Cygwin's Python's os.execv doesn't support unicode command
- # arguments, and neither does Cygwin's execv itself.
- if sys.platform == 'cygwin':
- return True
-
- # Win32 Python 2.x uses CreateProcessA rather than CreateProcessW
- # to launch subprocesses, so we have to encode arguments using the
- # current code page.
- if sys.platform == 'win32' and versioning.compare_version(sys, '3.0')[0] < 0:
- return True
-
- return False
-
- def _encode_argument_if_needed(self, argument):
- if not self._should_encode_child_process_arguments():
- return argument
- return argument.encode(self._child_process_encoding())
diff --git a/WebKitTools/Scripts/webkitpy/common/system/executive_mock.py b/WebKitTools/Scripts/webkitpy/common/system/executive_mock.py
deleted file mode 100644
index c1cf999..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/executive_mock.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# Copyright (C) 2009 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# FIXME: Implement the rest of the interface as needed for testing :).
-
-# FIXME: Unify with tool/mocktool.MockExecutive.
-
-
-class MockExecutive2(object):
- def __init__(self, output='', exit_code=0, exception=None,
- run_command_fn=None):
- self._output = output
- self._exit_code = exit_code
- self._exception = exception
- self._run_command_fn = run_command_fn
-
- def cpu_count(self):
- return 2
-
- def kill_all(self, process_name):
- pass
-
- def kill_process(self, pid):
- pass
-
- def run_command(self, arg_list, return_exit_code=False,
- decode_output=False):
- if self._exception:
- raise self._exception
- if return_exit_code:
- return self._exit_code
- if self._run_command_fn:
- return self._run_command_fn(arg_list)
- return self._output
diff --git a/WebKitTools/Scripts/webkitpy/common/system/executive_unittest.py b/WebKitTools/Scripts/webkitpy/common/system/executive_unittest.py
deleted file mode 100644
index b8fd82e..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/executive_unittest.py
+++ /dev/null
@@ -1,151 +0,0 @@
-# Copyright (C) 2010 Google Inc. All rights reserved.
-# Copyright (C) 2009 Daniel Bates (dbates@intudata.com). All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import os
-import signal
-import subprocess
-import sys
-import unittest
-
-from webkitpy.common.system.executive import Executive, run_command, ScriptError
-from webkitpy.test import cat, echo
-
-
-def never_ending_command():
- """Arguments for a command that will never end (useful for testing process
- killing). It should be a process that is unlikely to already be running
- because all instances will be killed."""
- if sys.platform == 'win32':
- return ['wmic']
- return ['yes']
-
-
-class ExecutiveTest(unittest.TestCase):
-
- def test_run_command_with_bad_command(self):
- def run_bad_command():
- run_command(["foo_bar_command_blah"], error_handler=Executive.ignore_error, return_exit_code=True)
- self.failUnlessRaises(OSError, run_bad_command)
-
- def test_run_command_args_type(self):
- executive = Executive()
- self.assertRaises(AssertionError, executive.run_command, "echo")
- self.assertRaises(AssertionError, executive.run_command, u"echo")
- executive.run_command(echo.command_arguments('foo'))
- executive.run_command(tuple(echo.command_arguments('foo')))
-
- def test_run_command_with_unicode(self):
- """Validate that it is safe to pass unicode() objects
- to Executive.run* methods, and they will return unicode()
- objects by default unless decode_output=False"""
- unicode_tor_input = u"WebKit \u2661 Tor Arne Vestb\u00F8!"
- if sys.platform == 'win32':
- encoding = 'mbcs'
- else:
- encoding = 'utf-8'
- encoded_tor = unicode_tor_input.encode(encoding)
- # On Windows, we expect the unicode->mbcs->unicode roundtrip to be
- # lossy. On other platforms, we expect a lossless roundtrip.
- if sys.platform == 'win32':
- unicode_tor_output = encoded_tor.decode(encoding)
- else:
- unicode_tor_output = unicode_tor_input
-
- executive = Executive()
-
- output = executive.run_command(cat.command_arguments(), input=unicode_tor_input)
- self.assertEquals(output, unicode_tor_output)
-
- output = executive.run_command(echo.command_arguments("-n", unicode_tor_input))
- self.assertEquals(output, unicode_tor_output)
-
- output = executive.run_command(echo.command_arguments("-n", unicode_tor_input), decode_output=False)
- self.assertEquals(output, encoded_tor)
-
- # Make sure that str() input also works.
- output = executive.run_command(cat.command_arguments(), input=encoded_tor, decode_output=False)
- self.assertEquals(output, encoded_tor)
-
- # FIXME: We should only have one run* method to test
- output = executive.run_and_throw_if_fail(echo.command_arguments("-n", unicode_tor_input), quiet=True)
- self.assertEquals(output, unicode_tor_output)
-
- output = executive.run_and_throw_if_fail(echo.command_arguments("-n", unicode_tor_input), quiet=True, decode_output=False)
- self.assertEquals(output, encoded_tor)
-
- def test_kill_process(self):
- executive = Executive()
- process = subprocess.Popen(never_ending_command(), stdout=subprocess.PIPE)
- self.assertEqual(process.poll(), None) # Process is running
- executive.kill_process(process.pid)
- # Note: Can't use a ternary since signal.SIGKILL is undefined for sys.platform == "win32"
- if sys.platform == "win32":
- expected_exit_code = 1
- else:
- expected_exit_code = -signal.SIGKILL
- self.assertEqual(process.wait(), expected_exit_code)
- # Killing again should fail silently.
- executive.kill_process(process.pid)
-
- def _assert_windows_image_name(self, name, expected_windows_name):
- executive = Executive()
- windows_name = executive._windows_image_name(name)
- self.assertEqual(windows_name, expected_windows_name)
-
- def test_windows_image_name(self):
- self._assert_windows_image_name("foo", "foo.exe")
- self._assert_windows_image_name("foo.exe", "foo.exe")
- self._assert_windows_image_name("foo.com", "foo.com")
- # If the name looks like an extension, even if it isn't
- # supposed to, we have no choice but to return the original name.
- self._assert_windows_image_name("foo.baz", "foo.baz")
- self._assert_windows_image_name("foo.baz.exe", "foo.baz.exe")
-
- def test_kill_all(self):
- executive = Executive()
- # We use "yes" because it loops forever.
- process = subprocess.Popen(never_ending_command(), stdout=subprocess.PIPE)
- self.assertEqual(process.poll(), None) # Process is running
- executive.kill_all(never_ending_command()[0])
- # Note: Can't use a ternary since signal.SIGTERM is undefined for sys.platform == "win32"
- if sys.platform == "cygwin":
- expected_exit_code = 0 # os.kill results in exit(0) for this process.
- elif sys.platform == "win32":
- expected_exit_code = 1
- else:
- expected_exit_code = -signal.SIGTERM
- self.assertEqual(process.wait(), expected_exit_code)
- # Killing again should fail silently.
- executive.kill_all(never_ending_command()[0])
-
- def test_check_running_pid(self):
- executive = Executive()
- self.assertTrue(executive.check_running_pid(os.getpid()))
- # Maximum pid number on Linux is 32768 by default
- self.assertFalse(executive.check_running_pid(100000))
diff --git a/WebKitTools/Scripts/webkitpy/common/system/file_lock.py b/WebKitTools/Scripts/webkitpy/common/system/file_lock.py
deleted file mode 100644
index 7296958..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/file_lock.py
+++ /dev/null
@@ -1,83 +0,0 @@
-#!/usr/bin/env python
-# Copyright (C) 2010 Gabor Rapcsanyi (rgabor@inf.u-szeged.hu), University of Szeged
-#
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY
-# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR
-# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
-# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""This class helps to lock files exclusively across processes."""
-
-import logging
-import os
-import sys
-import time
-
-
-_log = logging.getLogger("webkitpy.common.system.file_lock")
-
-
-class FileLock(object):
-
- def __init__(self, lock_file_path, max_wait_time_sec=20):
- self._lock_file_path = lock_file_path
- self._lock_file_descriptor = None
- self._max_wait_time_sec = max_wait_time_sec
-
- def _create_lock(self):
- if sys.platform in ('darwin', 'linux2', 'cygwin'):
- import fcntl
- fcntl.flock(self._lock_file_descriptor, fcntl.LOCK_EX | fcntl.LOCK_NB)
- elif sys.platform == 'win32':
- import msvcrt
- msvcrt.locking(self._lock_file_descriptor, msvcrt.LK_NBLCK, 32)
-
- def _remove_lock(self):
- if sys.platform in ('darwin', 'linux2', 'cygwin'):
- import fcntl
- fcntl.flock(self._lock_file_descriptor, fcntl.LOCK_UN)
- elif sys.platform == 'win32':
- import msvcrt
- msvcrt.locking(self._lock_file_descriptor, msvcrt.LK_UNLCK, 32)
-
- def acquire_lock(self):
- self._lock_file_descriptor = os.open(self._lock_file_path, os.O_TRUNC | os.O_CREAT)
- start_time = time.time()
- while True:
- try:
- self._create_lock()
- return True
- except IOError:
- if time.time() - start_time > self._max_wait_time_sec:
- _log.debug("File locking failed: %s" % str(sys.exc_info()))
- os.close(self._lock_file_descriptor)
- self._lock_file_descriptor = None
- return False
-
- def release_lock(self):
- try:
- if self._lock_file_descriptor:
- self._remove_lock()
- os.close(self._lock_file_descriptor)
- self._lock_file_descriptor = None
- os.unlink(self._lock_file_path)
- except (IOError, OSError):
- _log.debug("Warning in release lock: %s" % str(sys.exc_info()))
diff --git a/WebKitTools/Scripts/webkitpy/common/system/file_lock_unittest.py b/WebKitTools/Scripts/webkitpy/common/system/file_lock_unittest.py
deleted file mode 100644
index c5c1db3..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/file_lock_unittest.py
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/usr/bin/env python
-# Copyright (C) 2010 Gabor Rapcsanyi (rgabor@inf.u-szeged.hu), University of Szeged
-#
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY
-# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR
-# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
-# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import os
-import tempfile
-import unittest
-
-from webkitpy.common.system.file_lock import FileLock
-
-
-class FileLockTest(unittest.TestCase):
-
- def setUp(self):
- self._lock_name = "TestWebKit" + str(os.getpid()) + ".lock"
- self._lock_path = os.path.join(tempfile.gettempdir(), self._lock_name)
- self._file_lock1 = FileLock(self._lock_path, 1)
- self._file_lock2 = FileLock(self._lock_path, 1)
-
- def tearDown(self):
- self._file_lock1.release_lock()
- self._file_lock2.release_lock()
-
- def test_lock_lifecycle(self):
- # Create the lock.
- self._file_lock1.acquire_lock()
- self.assertTrue(os.path.exists(self._lock_path))
-
- # Try to lock again.
- self.assertFalse(self._file_lock2.acquire_lock())
-
- # Release the lock.
- self._file_lock1.release_lock()
- self.assertFalse(os.path.exists(self._lock_path))
-
- def test_stuck_lock(self):
- open(self._lock_path, 'w').close()
- self._file_lock1.acquire_lock()
- self._file_lock1.release_lock()
diff --git a/WebKitTools/Scripts/webkitpy/common/system/filesystem.py b/WebKitTools/Scripts/webkitpy/common/system/filesystem.py
deleted file mode 100644
index c7efde3..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/filesystem.py
+++ /dev/null
@@ -1,117 +0,0 @@
-# Copyright (C) 2010 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Wrapper object for the file system / source tree."""
-
-from __future__ import with_statement
-
-import codecs
-import errno
-import os
-import tempfile
-
-
-class FileSystem(object):
- """FileSystem interface for webkitpy.
-
- Unless otherwise noted, all paths are allowed to be either absolute
- or relative."""
-
- def exists(self, path):
- """Return whether the path exists in the filesystem."""
- return os.path.exists(path)
-
- def isdir(self, path):
- """Return whether the path refers to a directory."""
- return os.path.isdir(path)
-
- def join(self, *comps):
- """Return the path formed by joining the components."""
- return os.path.join(*comps)
-
- def listdir(self, path):
- """Return the contents of the directory pointed to by path."""
- return os.listdir(path)
-
- def mkdtemp(self, **kwargs):
- """Create and return a uniquely named directory.
-
- This is like tempfile.mkdtemp, but if used in a with statement
- the directory will self-delete at the end of the block (if the
- directory is empty; non-empty directories raise errors). The
- directory can be safely deleted inside the block as well, if so
- desired."""
- class TemporaryDirectory(object):
- def __init__(self, **kwargs):
- self._kwargs = kwargs
- self._directory_path = None
-
- def __enter__(self):
- self._directory_path = tempfile.mkdtemp(**self._kwargs)
- return self._directory_path
-
- def __exit__(self, type, value, traceback):
- # Only self-delete if necessary.
-
- # FIXME: Should we delete non-empty directories?
- if os.path.exists(self._directory_path):
- os.rmdir(self._directory_path)
-
- return TemporaryDirectory(**kwargs)
-
- def maybe_make_directory(self, *path):
- """Create the specified directory if it doesn't already exist."""
- try:
- os.makedirs(os.path.join(*path))
- except OSError, e:
- if e.errno != errno.EEXIST:
- raise
-
- def read_binary_file(self, path):
- """Return the contents of the file at the given path as a byte string."""
- with file(path, 'rb') as f:
- return f.read()
-
- def read_text_file(self, path):
- """Return the contents of the file at the given path as a Unicode string.
-
- The file is read assuming it is a UTF-8 encoded file with no BOM."""
- with codecs.open(path, 'r', 'utf8') as f:
- return f.read()
-
- def write_binary_file(self, path, contents):
- """Write the contents to the file at the given location."""
- with file(path, 'wb') as f:
- f.write(contents)
-
- def write_text_file(self, path, contents):
- """Write the contents to the file at the given location.
-
- The file is written encoded as UTF-8 with no BOM."""
- with codecs.open(path, 'w', 'utf8') as f:
- f.write(contents)
diff --git a/WebKitTools/Scripts/webkitpy/common/system/filesystem_mock.py b/WebKitTools/Scripts/webkitpy/common/system/filesystem_mock.py
deleted file mode 100644
index 4e6d3da..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/filesystem_mock.py
+++ /dev/null
@@ -1,80 +0,0 @@
-# Copyright (C) 2009 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import errno
-import os
-import path
-
-
-class MockFileSystem(object):
- def __init__(self, files={}):
- """Initializes a "mock" filesystem that can be used to completely
- stub out a filesystem.
-
- Args:
- files: a dict of filenames -> file contents. A file contents
- value of None is used to indicate that the file should
- not exist.
- """
- self.files = files
-
- def exists(self, path):
- if path in self.files:
- return self.files[path] is not None
- return False
-
- def join(self, *comps):
- # os.path.join ignores trailing slashes on components (i.e.
- # join('foo/', 'bar') and join('foo', 'bar') produce the same result),
- # we emulate that behavior.
- trimmed_comps = []
- for comp in comps:
- if len(comp) and comp[-1] == '/':
- trimmed_comps.append(comp[0:-1])
- else:
- trimmed_comps.append(comp)
- return '/'.join(trimmed_comps)
-
- def maybe_make_directory(self, *path):
- # FIXME: Implement such that subsequent calls to isdir() work?
- pass
-
- def read_text_file(self, path):
- return self.read_binary_file(path)
-
- def read_binary_file(self, path):
- if path in self.files:
- if self.files[path] is None:
- raise IOError(errno.ENOENT, path, os.strerror(errno.ENOENT))
- return self.files[path]
-
- def write_text_file(self, path, contents):
- return self.write_binary_file(path, contents)
-
- def write_binary_file(self, path, contents):
- self.files[path] = contents
diff --git a/WebKitTools/Scripts/webkitpy/common/system/filesystem_unittest.py b/WebKitTools/Scripts/webkitpy/common/system/filesystem_unittest.py
deleted file mode 100644
index 95684b7..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/filesystem_unittest.py
+++ /dev/null
@@ -1,157 +0,0 @@
-# vim: set fileencoding=utf-8 :
-# Copyright (C) 2010 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# NOTE: The fileencoding comment on the first line of the file is
-# important; without it, Python will choke while trying to parse the file,
-# since it includes non-ASCII characters.
-
-from __future__ import with_statement
-
-import os
-import stat
-import sys
-import tempfile
-import unittest
-
-from filesystem import FileSystem
-
-
-class FileSystemTest(unittest.TestCase):
- def setUp(self):
- self._this_dir = os.path.dirname(os.path.abspath(__file__))
- self._missing_file = os.path.join(self._this_dir, 'missing_file.py')
- self._this_file = os.path.join(self._this_dir, 'filesystem_unittest.py')
-
- def test_exists__true(self):
- fs = FileSystem()
- self.assertTrue(fs.exists(self._this_file))
-
- def test_exists__false(self):
- fs = FileSystem()
- self.assertFalse(fs.exists(self._missing_file))
-
- def test_isdir__true(self):
- fs = FileSystem()
- self.assertTrue(fs.isdir(self._this_dir))
-
- def test_isdir__false(self):
- fs = FileSystem()
- self.assertFalse(fs.isdir(self._this_file))
-
- def test_join(self):
- fs = FileSystem()
- self.assertEqual(fs.join('foo', 'bar'),
- os.path.join('foo', 'bar'))
-
- def test_listdir(self):
- fs = FileSystem()
- with fs.mkdtemp(prefix='filesystem_unittest_') as d:
- self.assertEqual(fs.listdir(d), [])
- new_file = os.path.join(d, 'foo')
- fs.write_text_file(new_file, u'foo')
- self.assertEqual(fs.listdir(d), ['foo'])
- os.remove(new_file)
-
- def test_maybe_make_directory__success(self):
- fs = FileSystem()
-
- with fs.mkdtemp(prefix='filesystem_unittest_') as base_path:
- sub_path = os.path.join(base_path, "newdir")
- self.assertFalse(os.path.exists(sub_path))
- self.assertFalse(fs.isdir(sub_path))
-
- fs.maybe_make_directory(sub_path)
- self.assertTrue(os.path.exists(sub_path))
- self.assertTrue(fs.isdir(sub_path))
-
- # Make sure we can re-create it.
- fs.maybe_make_directory(sub_path)
- self.assertTrue(os.path.exists(sub_path))
- self.assertTrue(fs.isdir(sub_path))
-
- # Clean up.
- os.rmdir(sub_path)
-
- self.assertFalse(os.path.exists(base_path))
- self.assertFalse(fs.isdir(base_path))
-
- def test_maybe_make_directory__failure(self):
- # FIXME: os.chmod() doesn't work on Windows to set directories
- # as readonly, so we skip this test for now.
- if sys.platform in ('win32', 'cygwin'):
- return
-
- fs = FileSystem()
- with fs.mkdtemp(prefix='filesystem_unittest_') as d:
- # Remove write permissions on the parent directory.
- os.chmod(d, stat.S_IRUSR)
-
- # Now try to create a sub directory - should fail.
- sub_dir = fs.join(d, 'subdir')
- self.assertRaises(OSError, fs.maybe_make_directory, sub_dir)
-
- # Clean up in case the test failed and we did create the
- # directory.
- if os.path.exists(sub_dir):
- os.rmdir(sub_dir)
-
- def test_read_and_write_file(self):
- fs = FileSystem()
- text_path = None
- binary_path = None
-
- unicode_text_string = u'Ūnĭcōde̽'
- hex_equivalent = '\xC5\xAA\x6E\xC4\xAD\x63\xC5\x8D\x64\x65\xCC\xBD'
- try:
- text_path = tempfile.mktemp(prefix='tree_unittest_')
- binary_path = tempfile.mktemp(prefix='tree_unittest_')
- fs.write_text_file(text_path, unicode_text_string)
- contents = fs.read_binary_file(text_path)
- self.assertEqual(contents, hex_equivalent)
-
- fs.write_text_file(binary_path, hex_equivalent)
- text_contents = fs.read_text_file(binary_path)
- self.assertEqual(text_contents, unicode_text_string)
- except:
- if text_path:
- os.remove(text_path)
- if binary_path:
- os.remove(binary_path)
-
- def test_read_binary_file__missing(self):
- fs = FileSystem()
- self.assertRaises(IOError, fs.read_binary_file, self._missing_file)
-
- def test_read_text_file__missing(self):
- fs = FileSystem()
- self.assertRaises(IOError, fs.read_text_file, self._missing_file)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/WebKitTools/Scripts/webkitpy/common/system/fileutils.py b/WebKitTools/Scripts/webkitpy/common/system/fileutils.py
deleted file mode 100644
index 55821f8..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/fileutils.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2010 Apple Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
-# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import sys
-
-
-def make_stdout_binary():
- """Puts sys.stdout into binary mode (on platforms that have a distinction
- between text and binary mode)."""
- if sys.platform != 'win32' or not hasattr(sys.stdout, 'fileno'):
- return
- import msvcrt
- import os
- msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
diff --git a/WebKitTools/Scripts/webkitpy/common/system/logtesting.py b/WebKitTools/Scripts/webkitpy/common/system/logtesting.py
deleted file mode 100644
index e361cb5..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/logtesting.py
+++ /dev/null
@@ -1,258 +0,0 @@
-# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org)
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
-# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Supports the unit-testing of logging code.
-
-Provides support for unit-testing messages logged using the built-in
-logging module.
-
-Inherit from the LoggingTestCase class for basic testing needs. For
-more advanced needs (e.g. unit-testing methods that configure logging),
-see the TestLogStream class, and perhaps also the LogTesting class.
-
-"""
-
-import logging
-import unittest
-
-
-class TestLogStream(object):
-
- """Represents a file-like object for unit-testing logging.
-
- This is meant for passing to the logging.StreamHandler constructor.
- Log messages captured by instances of this object can be tested
- using self.assertMessages() below.
-
- """
-
- def __init__(self, test_case):
- """Create an instance.
-
- Args:
- test_case: A unittest.TestCase instance.
-
- """
- self._test_case = test_case
- self.messages = []
- """A list of log messages written to the stream."""
-
- # Python documentation says that any object passed to the StreamHandler
- # constructor should support write() and flush():
- #
- # http://docs.python.org/library/logging.html#module-logging.handlers
- def write(self, message):
- self.messages.append(message)
-
- def flush(self):
- pass
-
- def assertMessages(self, messages):
- """Assert that the given messages match the logged messages.
-
- messages: A list of log message strings.
-
- """
- self._test_case.assertEquals(messages, self.messages)
-
-
-class LogTesting(object):
-
- """Supports end-to-end unit-testing of log messages.
-
- Sample usage:
-
- class SampleTest(unittest.TestCase):
-
- def setUp(self):
- self._log = LogTesting.setUp(self) # Turn logging on.
-
- def tearDown(self):
- self._log.tearDown() # Turn off and reset logging.
-
- def test_logging_in_some_method(self):
- call_some_method() # Contains calls to _log.info(), etc.
-
- # Check the resulting log messages.
- self._log.assertMessages(["INFO: expected message #1",
- "WARNING: expected message #2"])
-
- """
-
- def __init__(self, test_stream, handler):
- """Create an instance.
-
- This method should never be called directly. Instances should
- instead be created using the static setUp() method.
-
- Args:
- test_stream: A TestLogStream instance.
- handler: The handler added to the logger.
-
- """
- self._test_stream = test_stream
- self._handler = handler
-
- @staticmethod
- def _getLogger():
- """Return the logger being tested."""
- # It is possible we might want to return something other than
- # the root logger in some special situation. For now, the
- # root logger seems to suffice.
- return logging.getLogger()
-
- @staticmethod
- def setUp(test_case, logging_level=logging.INFO):
- """Configure logging for unit testing.
-
- Configures the root logger to log to a testing log stream.
- Only messages logged at or above the given level are logged
- to the stream. Messages logged to the stream are formatted
- in the following way, for example--
-
- "INFO: This is a test log message."
-
- This method should normally be called in the setUp() method
- of a unittest.TestCase. See the docstring of this class
- for more details.
-
- Returns:
- A LogTesting instance.
-
- Args:
- test_case: A unittest.TestCase instance.
- logging_level: An integer logging level that is the minimum level
- of log messages you would like to test.
-
- """
- stream = TestLogStream(test_case)
- handler = logging.StreamHandler(stream)
- handler.setLevel(logging_level)
- formatter = logging.Formatter("%(levelname)s: %(message)s")
- handler.setFormatter(formatter)
-
- # Notice that we only change the root logger by adding a handler
- # to it. In particular, we do not reset its level using
- # logger.setLevel(). This ensures that we have not interfered
- # with how the code being tested may have configured the root
- # logger.
- logger = LogTesting._getLogger()
- logger.addHandler(handler)
-
- return LogTesting(stream, handler)
-
- def tearDown(self):
- """Assert there are no remaining log messages, and reset logging.
-
- This method asserts that there are no more messages in the array of
- log messages, and then restores logging to its original state.
- This method should normally be called in the tearDown() method of a
- unittest.TestCase. See the docstring of this class for more details.
-
- """
- self.assertMessages([])
- logger = LogTesting._getLogger()
- logger.removeHandler(self._handler)
-
- def messages(self):
- """Return the current list of log messages."""
- return self._test_stream.messages
-
- # FIXME: Add a clearMessages() method for cases where the caller
- # deliberately doesn't want to assert every message.
-
- # We clear the log messages after asserting since they are no longer
- # needed after asserting. This serves two purposes: (1) it simplifies
- # the calling code when we want to check multiple logging calls in a
- # single test method, and (2) it lets us check in the tearDown() method
- # that there are no remaining log messages to be asserted.
- #
- # The latter ensures that no extra log messages are getting logged that
- # the caller might not be aware of or may have forgotten to check for.
- # This gets us a bit more mileage out of our tests without writing any
- # additional code.
- def assertMessages(self, messages):
- """Assert the current array of log messages, and clear its contents.
-
- Args:
- messages: A list of log message strings.
-
- """
- try:
- self._test_stream.assertMessages(messages)
- finally:
- # We want to clear the array of messages even in the case of
- # an Exception (e.g. an AssertionError). Otherwise, another
- # AssertionError can occur in the tearDown() because the
- # array might not have gotten emptied.
- self._test_stream.messages = []
-
-
-# This class needs to inherit from unittest.TestCase. Otherwise, the
-# setUp() and tearDown() methods will not get fired for test case classes
-# that inherit from this class -- even if the class inherits from *both*
-# unittest.TestCase and LoggingTestCase.
-#
-# FIXME: Rename this class to LoggingTestCaseBase to be sure that
-# the unittest module does not interpret this class as a unittest
-# test case itself.
-class LoggingTestCase(unittest.TestCase):
-
- """Supports end-to-end unit-testing of log messages.
-
- Sample usage:
-
- class SampleTest(LoggingTestCase):
-
- def test_logging_in_some_method(self):
- call_some_method() # Contains calls to _log.info(), etc.
-
- # Check the resulting log messages.
- self.assertLog(["INFO: expected message #1",
- "WARNING: expected message #2"])
-
- """
-
- def setUp(self):
- self._log = LogTesting.setUp(self)
-
- def tearDown(self):
- self._log.tearDown()
-
- def logMessages(self):
- """Return the current list of log messages."""
- return self._log.messages()
-
- # FIXME: Add a clearMessages() method for cases where the caller
- # deliberately doesn't want to assert every message.
-
- # See the code comments preceding LogTesting.assertMessages() for
- # an explanation of why we clear the array of messages after
- # asserting its contents.
- def assertLog(self, messages):
- """Assert the current array of log messages, and clear its contents.
-
- Args:
- messages: A list of log message strings.
-
- """
- self._log.assertMessages(messages)
diff --git a/WebKitTools/Scripts/webkitpy/common/system/logutils.py b/WebKitTools/Scripts/webkitpy/common/system/logutils.py
deleted file mode 100644
index cd4e60f..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/logutils.py
+++ /dev/null
@@ -1,207 +0,0 @@
-# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org)
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
-# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Supports webkitpy logging."""
-
-# FIXME: Move this file to webkitpy/python24 since logging needs to
-# be configured prior to running version-checking code.
-
-import logging
-import os
-import sys
-
-import webkitpy
-
-
-_log = logging.getLogger(__name__)
-
-# We set these directory paths lazily in get_logger() below.
-_scripts_dir = ""
-"""The normalized, absolute path to the ...Scripts directory."""
-
-_webkitpy_dir = ""
-"""The normalized, absolute path to the ...Scripts/webkitpy directory."""
-
-
-def _normalize_path(path):
- """Return the given path normalized.
-
- Converts a path to an absolute path, removes any trailing slashes,
- removes any extension, and lower-cases it.
-
- """
- path = os.path.abspath(path)
- path = os.path.normpath(path)
- path = os.path.splitext(path)[0] # Remove the extension, if any.
- path = path.lower()
-
- return path
-
-
-# Observe that the implementation of this function does not require
-# the use of any hard-coded strings like "webkitpy", etc.
-#
-# The main benefit this function has over using--
-#
-# _log = logging.getLogger(__name__)
-#
-# is that get_logger() returns the same value even if __name__ is
-# "__main__" -- i.e. even if the module is the script being executed
-# from the command-line.
-def get_logger(path):
- """Return a logging.logger for the given path.
-
- Returns:
- A logger whose name is the name of the module corresponding to
- the given path. If the module is in webkitpy, the name is
- the fully-qualified dotted module name beginning with webkitpy....
- Otherwise, the name is the base name of the module (i.e. without
- any dotted module name prefix).
-
- Args:
- path: The path of the module. Normally, this parameter should be
- the __file__ variable of the module.
-
- Sample usage:
-
- import webkitpy.common.system.logutils as logutils
-
- _log = logutils.get_logger(__file__)
-
- """
- # Since we assign to _scripts_dir and _webkitpy_dir in this function,
- # we need to declare them global.
- global _scripts_dir
- global _webkitpy_dir
-
- path = _normalize_path(path)
-
- # Lazily evaluate _webkitpy_dir and _scripts_dir.
- if not _scripts_dir:
- # The normalized, absolute path to ...Scripts/webkitpy/__init__.
- webkitpy_path = _normalize_path(webkitpy.__file__)
-
- _webkitpy_dir = os.path.split(webkitpy_path)[0]
- _scripts_dir = os.path.split(_webkitpy_dir)[0]
-
- if path.startswith(_webkitpy_dir):
- # Remove the initial Scripts directory portion, so the path
- # starts with /webkitpy, for example "/webkitpy/init/logutils".
- path = path[len(_scripts_dir):]
-
- parts = []
- while True:
- (path, tail) = os.path.split(path)
- if not tail:
- break
- parts.insert(0, tail)
-
- logger_name = ".".join(parts) # For example, webkitpy.common.system.logutils.
- else:
- # The path is outside of webkitpy. Default to the basename
- # without the extension.
- basename = os.path.basename(path)
- logger_name = os.path.splitext(basename)[0]
-
- return logging.getLogger(logger_name)
-
-
-def _default_handlers(stream):
- """Return a list of the default logging handlers to use.
-
- Args:
- stream: See the configure_logging() docstring.
-
- """
- # Create the filter.
- def should_log(record):
- """Return whether a logging.LogRecord should be logged."""
- # FIXME: Enable the logging of autoinstall messages once
- # autoinstall is adjusted. Currently, autoinstall logs
- # INFO messages when importing already-downloaded packages,
- # which is too verbose.
- if record.name.startswith("webkitpy.thirdparty.autoinstall"):
- return False
- return True
-
- logging_filter = logging.Filter()
- logging_filter.filter = should_log
-
- # Create the handler.
- handler = logging.StreamHandler(stream)
- formatter = logging.Formatter("%(name)s: [%(levelname)s] %(message)s")
- handler.setFormatter(formatter)
- handler.addFilter(logging_filter)
-
- return [handler]
-
-
-def configure_logging(logging_level=None, logger=None, stream=None,
- handlers=None):
- """Configure logging for standard purposes.
-
- Returns:
- A list of references to the logging handlers added to the root
- logger. This allows the caller to later remove the handlers
- using logger.removeHandler. This is useful primarily during unit
- testing where the caller may want to configure logging temporarily
- and then undo the configuring.
-
- Args:
- logging_level: The minimum logging level to log. Defaults to
- logging.INFO.
- logger: A logging.logger instance to configure. This parameter
- should be used only in unit tests. Defaults to the
- root logger.
- stream: A file-like object to which to log used in creating the default
- handlers. The stream must define an "encoding" data attribute,
- or else logging raises an error. Defaults to sys.stderr.
- handlers: A list of logging.Handler instances to add to the logger
- being configured. If this parameter is provided, then the
- stream parameter is not used.
-
- """
- # If the stream does not define an "encoding" data attribute, the
- # logging module can throw an error like the following:
- #
- # Traceback (most recent call last):
- # File "/System/Library/Frameworks/Python.framework/Versions/2.6/...
- # lib/python2.6/logging/__init__.py", line 761, in emit
- # self.stream.write(fs % msg.encode(self.stream.encoding))
- # LookupError: unknown encoding: unknown
- if logging_level is None:
- logging_level = logging.INFO
- if logger is None:
- logger = logging.getLogger()
- if stream is None:
- stream = sys.stderr
- if handlers is None:
- handlers = _default_handlers(stream)
-
- logger.setLevel(logging_level)
-
- for handler in handlers:
- logger.addHandler(handler)
-
- _log.debug("Debug logging enabled.")
-
- return handlers
diff --git a/WebKitTools/Scripts/webkitpy/common/system/logutils_unittest.py b/WebKitTools/Scripts/webkitpy/common/system/logutils_unittest.py
deleted file mode 100644
index a4a6496..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/logutils_unittest.py
+++ /dev/null
@@ -1,142 +0,0 @@
-# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org)
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
-# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Unit tests for logutils.py."""
-
-import logging
-import os
-import unittest
-
-from webkitpy.common.system.logtesting import LogTesting
-from webkitpy.common.system.logtesting import TestLogStream
-import webkitpy.common.system.logutils as logutils
-
-
-class GetLoggerTest(unittest.TestCase):
-
- """Tests get_logger()."""
-
- def test_get_logger_in_webkitpy(self):
- logger = logutils.get_logger(__file__)
- self.assertEquals(logger.name, "webkitpy.common.system.logutils_unittest")
-
- def test_get_logger_not_in_webkitpy(self):
- # Temporarily change the working directory so that we
- # can test get_logger() for a path outside of webkitpy.
- working_directory = os.getcwd()
- root_dir = "/"
- os.chdir(root_dir)
-
- logger = logutils.get_logger("/WebKitTools/Scripts/test-webkitpy")
- self.assertEquals(logger.name, "test-webkitpy")
-
- logger = logutils.get_logger("/WebKitTools/Scripts/test-webkitpy.py")
- self.assertEquals(logger.name, "test-webkitpy")
-
- os.chdir(working_directory)
-
-
-class ConfigureLoggingTestBase(unittest.TestCase):
-
- """Base class for configure_logging() unit tests."""
-
- def _logging_level(self):
- raise Exception("Not implemented.")
-
- def setUp(self):
- log_stream = TestLogStream(self)
-
- # Use a logger other than the root logger or one prefixed with
- # "webkitpy." so as not to conflict with test-webkitpy logging.
- logger = logging.getLogger("unittest")
-
- # Configure the test logger not to pass messages along to the
- # root logger. This prevents test messages from being
- # propagated to loggers used by test-webkitpy logging (e.g.
- # the root logger).
- logger.propagate = False
-
- logging_level = self._logging_level()
- self._handlers = logutils.configure_logging(logging_level=logging_level,
- logger=logger,
- stream=log_stream)
- self._log = logger
- self._log_stream = log_stream
-
- def tearDown(self):
- """Reset logging to its original state.
-
- This method ensures that the logging configuration set up
- for a unit test does not affect logging in other unit tests.
-
- """
- logger = self._log
- for handler in self._handlers:
- logger.removeHandler(handler)
-
- def _assert_log_messages(self, messages):
- """Assert that the logged messages equal the given messages."""
- self._log_stream.assertMessages(messages)
-
-
-class ConfigureLoggingTest(ConfigureLoggingTestBase):
-
- """Tests configure_logging() with the default logging level."""
-
- def _logging_level(self):
- return None
-
- def test_info_message(self):
- self._log.info("test message")
- self._assert_log_messages(["unittest: [INFO] test message\n"])
-
- def test_below_threshold_message(self):
- # We test the boundary case of a logging level equal to 19.
- # In practice, we will probably only be calling log.debug(),
- # which corresponds to a logging level of 10.
- level = logging.INFO - 1 # Equals 19.
- self._log.log(level, "test message")
- self._assert_log_messages([])
-
- def test_two_messages(self):
- self._log.info("message1")
- self._log.info("message2")
- self._assert_log_messages(["unittest: [INFO] message1\n",
- "unittest: [INFO] message2\n"])
-
-
-class ConfigureLoggingCustomLevelTest(ConfigureLoggingTestBase):
-
- """Tests configure_logging() with a custom logging level."""
-
- _level = 36
-
- def _logging_level(self):
- return self._level
-
- def test_logged_message(self):
- self._log.log(self._level, "test message")
- self._assert_log_messages(["unittest: [Level 36] test message\n"])
-
- def test_below_threshold_message(self):
- self._log.log(self._level - 1, "test message")
- self._assert_log_messages([])
diff --git a/WebKitTools/Scripts/webkitpy/common/system/ospath.py b/WebKitTools/Scripts/webkitpy/common/system/ospath.py
deleted file mode 100644
index aed7a3d..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/ospath.py
+++ /dev/null
@@ -1,83 +0,0 @@
-# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org)
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
-# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Contains a substitute for Python 2.6's os.path.relpath()."""
-
-import os
-
-
-# This function is a replacement for os.path.relpath(), which is only
-# available in Python 2.6:
-#
-# http://docs.python.org/library/os.path.html#os.path.relpath
-#
-# It should behave essentially the same as os.path.relpath(), except for
-# returning None on paths not contained in abs_start_path.
-def relpath(path, start_path, os_path_abspath=None):
- """Return a path relative to the given start path, or None.
-
- Returns None if the path is not contained in the directory start_path.
-
- Args:
- path: An absolute or relative path to convert to a relative path.
- start_path: The path relative to which the given path should be
- converted.
- os_path_abspath: A replacement function for unit testing. This
- function should strip trailing slashes just like
- os.path.abspath(). Defaults to os.path.abspath.
-
- """
- if os_path_abspath is None:
- os_path_abspath = os.path.abspath
-
- # Since os_path_abspath() calls os.path.normpath()--
- #
- # (see http://docs.python.org/library/os.path.html#os.path.abspath )
- #
- # it also removes trailing slashes and converts forward and backward
- # slashes to the preferred slash os.sep.
- start_path = os_path_abspath(start_path)
- path = os_path_abspath(path)
-
- if not path.lower().startswith(start_path.lower()):
- # Then path is outside the directory given by start_path.
- return None
-
- rel_path = path[len(start_path):]
-
- if not rel_path:
- # Then the paths are the same.
- pass
- elif rel_path[0] == os.sep:
- # It is probably sufficient to remove just the first character
- # since os.path.normpath() collapses separators, but we use
- # lstrip() just to be sure.
- rel_path = rel_path.lstrip(os.sep)
- else:
- # We are in the case typified by the following example:
- #
- # start_path = "/tmp/foo"
- # path = "/tmp/foobar"
- # rel_path = "bar"
- return None
-
- return rel_path
diff --git a/WebKitTools/Scripts/webkitpy/common/system/ospath_unittest.py b/WebKitTools/Scripts/webkitpy/common/system/ospath_unittest.py
deleted file mode 100644
index 0493c68..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/ospath_unittest.py
+++ /dev/null
@@ -1,62 +0,0 @@
-# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org)
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
-# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Unit tests for ospath.py."""
-
-import os
-import unittest
-
-from webkitpy.common.system.ospath import relpath
-
-
-# Make sure the tests in this class are platform independent.
-class RelPathTest(unittest.TestCase):
-
- """Tests relpath()."""
-
- os_path_abspath = lambda self, path: path
-
- def _rel_path(self, path, abs_start_path):
- return relpath(path, abs_start_path, self.os_path_abspath)
-
- def test_same_path(self):
- rel_path = self._rel_path("WebKit", "WebKit")
- self.assertEquals(rel_path, "")
-
- def test_long_rel_path(self):
- start_path = "WebKit"
- expected_rel_path = os.path.join("test", "Foo.txt")
- path = os.path.join(start_path, expected_rel_path)
-
- rel_path = self._rel_path(path, start_path)
- self.assertEquals(expected_rel_path, rel_path)
-
- def test_none_rel_path(self):
- """Test _rel_path() with None return value."""
- start_path = "WebKit"
- path = os.path.join("other_dir", "foo.txt")
-
- rel_path = self._rel_path(path, start_path)
- self.assertTrue(rel_path is None)
-
- rel_path = self._rel_path("WebKitTools", "WebKit")
- self.assertTrue(rel_path is None)
diff --git a/WebKitTools/Scripts/webkitpy/common/system/outputcapture.py b/WebKitTools/Scripts/webkitpy/common/system/outputcapture.py
deleted file mode 100644
index 45e0e3f..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/outputcapture.py
+++ /dev/null
@@ -1,86 +0,0 @@
-# Copyright (c) 2009, Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# Class for unittest support. Used for capturing stderr/stdout.
-
-import sys
-import unittest
-from StringIO import StringIO
-
-class OutputCapture(object):
- def __init__(self):
- self.saved_outputs = dict()
-
- def _capture_output_with_name(self, output_name):
- self.saved_outputs[output_name] = getattr(sys, output_name)
- captured_output = StringIO()
- setattr(sys, output_name, captured_output)
- return captured_output
-
- def _restore_output_with_name(self, output_name):
- captured_output = getattr(sys, output_name).getvalue()
- setattr(sys, output_name, self.saved_outputs[output_name])
- del self.saved_outputs[output_name]
- return captured_output
-
- def capture_output(self):
- return (self._capture_output_with_name("stdout"), self._capture_output_with_name("stderr"))
-
- def restore_output(self):
- return (self._restore_output_with_name("stdout"), self._restore_output_with_name("stderr"))
-
- def assert_outputs(self, testcase, function, args=[], kwargs={}, expected_stdout="", expected_stderr="", expected_exception=None):
- self.capture_output()
- if expected_exception:
- return_value = testcase.assertRaises(expected_exception, function, *args, **kwargs)
- else:
- return_value = function(*args, **kwargs)
- (stdout_string, stderr_string) = self.restore_output()
- testcase.assertEqual(stdout_string, expected_stdout)
- testcase.assertEqual(stderr_string, expected_stderr)
- # This is a little strange, but I don't know where else to return this information.
- return return_value
-
-
-class OutputCaptureTestCaseBase(unittest.TestCase):
- def setUp(self):
- unittest.TestCase.setUp(self)
- self.output_capture = OutputCapture()
- (self.__captured_stdout, self.__captured_stderr) = self.output_capture.capture_output()
-
- def tearDown(self):
- del self.__captured_stdout
- del self.__captured_stderr
- self.output_capture.restore_output()
- unittest.TestCase.tearDown(self)
-
- def assertStdout(self, expected_stdout):
- self.assertEquals(expected_stdout, self.__captured_stdout.getvalue())
-
- def assertStderr(self, expected_stderr):
- self.assertEquals(expected_stderr, self.__captured_stderr.getvalue())
diff --git a/WebKitTools/Scripts/webkitpy/common/system/path.py b/WebKitTools/Scripts/webkitpy/common/system/path.py
deleted file mode 100644
index 09787d7..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/path.py
+++ /dev/null
@@ -1,138 +0,0 @@
-# Copyright (C) 2010 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""generic routines to convert platform-specific paths to URIs."""
-from __future__ import with_statement
-
-import atexit
-import subprocess
-import sys
-import threading
-import urllib
-
-
-def abspath_to_uri(path, platform=None):
- """Converts a platform-specific absolute path to a file: URL."""
- if platform is None:
- platform = sys.platform
- return "file:" + _escape(_convert_path(path, platform))
-
-
-def cygpath(path):
- """Converts an absolute cygwin path to an absolute Windows path."""
- return _CygPath.convert_using_singleton(path)
-
-
-# Note that this object is not threadsafe and must only be called
-# from multiple threads under protection of a lock (as is done in cygpath())
-class _CygPath(object):
- """Manages a long-running 'cygpath' process for file conversion."""
- _lock = None
- _singleton = None
-
- @staticmethod
- def stop_cygpath_subprocess():
- if not _CygPath._lock:
- return
-
- with _CygPath._lock:
- if _CygPath._singleton:
- _CygPath._singleton.stop()
-
- @staticmethod
- def convert_using_singleton(path):
- if not _CygPath._lock:
- _CygPath._lock = threading.Lock()
-
- with _CygPath._lock:
- if not _CygPath._singleton:
- _CygPath._singleton = _CygPath()
- # Make sure the cygpath subprocess always gets shutdown cleanly.
- atexit.register(_CygPath.stop_cygpath_subprocess)
-
- return _CygPath._singleton.convert(path)
-
- def __init__(self):
- self._child_process = None
-
- def start(self):
- assert(self._child_process is None)
- args = ['cygpath', '-f', '-', '-wa']
- self._child_process = subprocess.Popen(args,
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE)
-
- def is_running(self):
- if not self._child_process:
- return False
- return self._child_process.returncode is None
-
- def stop(self):
- if self._child_process:
- self._child_process.stdin.close()
- self._child_process.wait()
- self._child_process = None
-
- def convert(self, path):
- if not self.is_running():
- self.start()
- self._child_process.stdin.write("%s\r\n" % path)
- self._child_process.stdin.flush()
- windows_path = self._child_process.stdout.readline().rstrip()
- # Some versions of cygpath use lowercase drive letters while others
- # use uppercase. We always convert to uppercase for consistency.
- windows_path = '%s%s' % (windows_path[0].upper(), windows_path[1:])
- return windows_path
-
-
-def _escape(path):
- """Handle any characters in the path that should be escaped."""
- # FIXME: web browsers don't appear to blindly quote every character
- # when converting filenames to files. Instead of using urllib's default
- # rules, we allow a small list of other characters through un-escaped.
- # It's unclear if this is the best possible solution.
- return urllib.quote(path, safe='/+:')
-
-
-def _convert_path(path, platform):
- """Handles any os-specific path separators, mappings, etc."""
- if platform == 'win32':
- return _winpath_to_uri(path)
- if platform == 'cygwin':
- return _winpath_to_uri(cygpath(path))
- return _unixypath_to_uri(path)
-
-
-def _winpath_to_uri(path):
- """Converts a window absolute path to a file: URL."""
- return "///" + path.replace("\\", "/")
-
-
-def _unixypath_to_uri(path):
- """Converts a unix-style path to a file: URL."""
- return "//" + path
diff --git a/WebKitTools/Scripts/webkitpy/common/system/path_unittest.py b/WebKitTools/Scripts/webkitpy/common/system/path_unittest.py
deleted file mode 100644
index 4dbd38a..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/path_unittest.py
+++ /dev/null
@@ -1,105 +0,0 @@
-# Copyright (C) 2010 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import unittest
-import sys
-
-import path
-
-class AbspathTest(unittest.TestCase):
- def assertMatch(self, test_path, expected_uri,
- platform=None):
- if platform == 'cygwin' and sys.platform != 'cygwin':
- return
- self.assertEqual(path.abspath_to_uri(test_path, platform=platform),
- expected_uri)
-
- def test_abspath_to_uri_cygwin(self):
- if sys.platform != 'cygwin':
- return
-
- self.assertMatch('/cygdrive/c/foo/bar.html',
- 'file:///C:/foo/bar.html',
- platform='cygwin')
- self.assertEqual(path.abspath_to_uri('/cygdrive/c/foo/bar.html',
- platform='cygwin'),
- 'file:///C:/foo/bar.html')
-
- def test_abspath_to_uri_darwin(self):
- self.assertMatch('/foo/bar.html',
- 'file:///foo/bar.html',
- platform='darwin')
- self.assertEqual(path.abspath_to_uri("/foo/bar.html",
- platform='darwin'),
- "file:///foo/bar.html")
-
- def test_abspath_to_uri_linux2(self):
- self.assertMatch('/foo/bar.html',
- 'file:///foo/bar.html',
- platform='darwin')
- self.assertEqual(path.abspath_to_uri("/foo/bar.html",
- platform='linux2'),
- "file:///foo/bar.html")
-
- def test_abspath_to_uri_win(self):
- self.assertMatch('c:\\foo\\bar.html',
- 'file:///c:/foo/bar.html',
- platform='win32')
- self.assertEqual(path.abspath_to_uri("c:\\foo\\bar.html",
- platform='win32'),
- "file:///c:/foo/bar.html")
-
- def test_abspath_to_uri_escaping(self):
- self.assertMatch('/foo/bar + baz%?.html',
- 'file:///foo/bar%20+%20baz%25%3F.html',
- platform='darwin')
- self.assertMatch('/foo/bar + baz%?.html',
- 'file:///foo/bar%20+%20baz%25%3F.html',
- platform='linux2')
-
- # Note that you can't have '?' in a filename on windows.
- self.assertMatch('/cygdrive/c/foo/bar + baz%.html',
- 'file:///C:/foo/bar%20+%20baz%25.html',
- platform='cygwin')
-
- def test_stop_cygpath_subprocess(self):
- if sys.platform != 'cygwin':
- return
-
- # Call cygpath to ensure the subprocess is running.
- path.cygpath("/cygdrive/c/foo.txt")
- self.assertTrue(path._CygPath._singleton.is_running())
-
- # Stop it.
- path._CygPath.stop_cygpath_subprocess()
-
- # Ensure that it is stopped.
- self.assertFalse(path._CygPath._singleton.is_running())
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/WebKitTools/Scripts/webkitpy/common/system/user.py b/WebKitTools/Scripts/webkitpy/common/system/user.py
deleted file mode 100644
index 8917137..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/user.py
+++ /dev/null
@@ -1,143 +0,0 @@
-# Copyright (c) 2009, Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import logging
-import os
-import re
-import shlex
-import subprocess
-import sys
-import webbrowser
-
-
-_log = logging.getLogger("webkitpy.common.system.user")
-
-
-try:
- import readline
-except ImportError:
- if sys.platform != "win32":
- # There is no readline module for win32, not much to do except cry.
- _log.warn("Unable to import readline.")
- # FIXME: We could give instructions for non-mac platforms.
- # Lack of readline results in a very bad user experiance.
- if sys.platform == "mac":
- _log.warn("If you're using MacPorts, try running:")
- _log.warn(" sudo port install py25-readline")
-
-
-class User(object):
- DEFAULT_NO = 'n'
- DEFAULT_YES = 'y'
-
- # FIXME: These are @classmethods because bugzilla.py doesn't have a Tool object (thus no User instance).
- @classmethod
- def prompt(cls, message, repeat=1, raw_input=raw_input):
- response = None
- while (repeat and not response):
- repeat -= 1
- response = raw_input(message)
- return response
-
- @classmethod
- def prompt_with_list(cls, list_title, list_items, can_choose_multiple=False, raw_input=raw_input):
- print list_title
- i = 0
- for item in list_items:
- i += 1
- print "%2d. %s" % (i, item)
-
- # Loop until we get valid input
- while True:
- if can_choose_multiple:
- response = cls.prompt("Enter one or more numbers (comma-separated), or \"all\": ", raw_input=raw_input)
- if not response.strip() or response == "all":
- return list_items
- try:
- indices = [int(r) - 1 for r in re.split("\s*,\s*", response)]
- except ValueError, err:
- continue
- return [list_items[i] for i in indices]
- else:
- try:
- result = int(cls.prompt("Enter a number: ", raw_input=raw_input)) - 1
- except ValueError, err:
- continue
- return list_items[result]
-
- def edit(self, files):
- editor = os.environ.get("EDITOR") or "vi"
- args = shlex.split(editor)
- # Note: Not thread safe: http://bugs.python.org/issue2320
- subprocess.call(args + files)
-
- def _warn_if_application_is_xcode(self, edit_application):
- if "Xcode" in edit_application:
- print "Instead of using Xcode.app, consider using EDITOR=\"xed --wait\"."
-
- def edit_changelog(self, files):
- edit_application = os.environ.get("CHANGE_LOG_EDIT_APPLICATION")
- if edit_application and sys.platform == "darwin":
- # On Mac we support editing ChangeLogs using an application.
- args = shlex.split(edit_application)
- print "Using editor in the CHANGE_LOG_EDIT_APPLICATION environment variable."
- print "Please quit the editor application when done editing."
- self._warn_if_application_is_xcode(edit_application)
- subprocess.call(["open", "-W", "-n", "-a"] + args + files)
- return
- self.edit(files)
-
- def page(self, message):
- pager = os.environ.get("PAGER") or "less"
- try:
- # Note: Not thread safe: http://bugs.python.org/issue2320
- child_process = subprocess.Popen([pager], stdin=subprocess.PIPE)
- child_process.communicate(input=message)
- except IOError, e:
- pass
-
- def confirm(self, message=None, default=DEFAULT_YES, raw_input=raw_input):
- if not message:
- message = "Continue?"
- choice = {'y': 'Y/n', 'n': 'y/N'}[default]
- response = raw_input("%s [%s]: " % (message, choice))
- if not response:
- response = default
- return response.lower() == 'y'
-
- def can_open_url(self):
- try:
- webbrowser.get()
- return True
- except webbrowser.Error, e:
- return False
-
- def open_url(self, url):
- if not self.can_open_url():
- _log.warn("Failed to open %s" % url)
- webbrowser.open(url)
diff --git a/WebKitTools/Scripts/webkitpy/common/system/user_unittest.py b/WebKitTools/Scripts/webkitpy/common/system/user_unittest.py
deleted file mode 100644
index 7ec9b34..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/user_unittest.py
+++ /dev/null
@@ -1,109 +0,0 @@
-# Copyright (C) 2010 Research in Motion Ltd. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Research in Motion Ltd. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import unittest
-
-from webkitpy.common.system.outputcapture import OutputCapture
-from webkitpy.common.system.user import User
-
-class UserTest(unittest.TestCase):
-
- example_user_response = "example user response"
-
- def test_prompt_repeat(self):
- self.repeatsRemaining = 2
- def mock_raw_input(message):
- self.repeatsRemaining -= 1
- if not self.repeatsRemaining:
- return UserTest.example_user_response
- return None
- self.assertEqual(User.prompt("input", repeat=self.repeatsRemaining, raw_input=mock_raw_input), UserTest.example_user_response)
-
- def test_prompt_when_exceeded_repeats(self):
- self.repeatsRemaining = 2
- def mock_raw_input(message):
- self.repeatsRemaining -= 1
- return None
- self.assertEqual(User.prompt("input", repeat=self.repeatsRemaining, raw_input=mock_raw_input), None)
-
- def test_prompt_with_list(self):
- def run_prompt_test(inputs, expected_result, can_choose_multiple=False):
- def mock_raw_input(message):
- return inputs.pop(0)
- output_capture = OutputCapture()
- actual_result = output_capture.assert_outputs(
- self,
- User.prompt_with_list,
- args=["title", ["foo", "bar"]],
- kwargs={"can_choose_multiple": can_choose_multiple, "raw_input": mock_raw_input},
- expected_stdout="title\n 1. foo\n 2. bar\n")
- self.assertEqual(actual_result, expected_result)
- self.assertEqual(len(inputs), 0)
-
- run_prompt_test(["1"], "foo")
- run_prompt_test(["badinput", "2"], "bar")
-
- run_prompt_test(["1,2"], ["foo", "bar"], can_choose_multiple=True)
- run_prompt_test([" 1, 2 "], ["foo", "bar"], can_choose_multiple=True)
- run_prompt_test(["all"], ["foo", "bar"], can_choose_multiple=True)
- run_prompt_test([""], ["foo", "bar"], can_choose_multiple=True)
- run_prompt_test([" "], ["foo", "bar"], can_choose_multiple=True)
- run_prompt_test(["badinput", "all"], ["foo", "bar"], can_choose_multiple=True)
-
- def test_confirm(self):
- test_cases = (
- (("Continue? [Y/n]: ", True), (User.DEFAULT_YES, 'y')),
- (("Continue? [Y/n]: ", False), (User.DEFAULT_YES, 'n')),
- (("Continue? [Y/n]: ", True), (User.DEFAULT_YES, '')),
- (("Continue? [Y/n]: ", False), (User.DEFAULT_YES, 'q')),
- (("Continue? [y/N]: ", True), (User.DEFAULT_NO, 'y')),
- (("Continue? [y/N]: ", False), (User.DEFAULT_NO, 'n')),
- (("Continue? [y/N]: ", False), (User.DEFAULT_NO, '')),
- (("Continue? [y/N]: ", False), (User.DEFAULT_NO, 'q')),
- )
- for test_case in test_cases:
- expected, inputs = test_case
-
- def mock_raw_input(message):
- self.assertEquals(expected[0], message)
- return inputs[1]
-
- result = User().confirm(default=inputs[0],
- raw_input=mock_raw_input)
- self.assertEquals(expected[1], result)
-
- def test_warn_if_application_is_xcode(self):
- output = OutputCapture()
- user = User()
- output.assert_outputs(self, user._warn_if_application_is_xcode, ["TextMate"])
- output.assert_outputs(self, user._warn_if_application_is_xcode, ["/Applications/TextMate.app"])
- output.assert_outputs(self, user._warn_if_application_is_xcode, ["XCode"]) # case sensitive matching
-
- xcode_warning = "Instead of using Xcode.app, consider using EDITOR=\"xed --wait\".\n"
- output.assert_outputs(self, user._warn_if_application_is_xcode, ["Xcode"], expected_stdout=xcode_warning)
- output.assert_outputs(self, user._warn_if_application_is_xcode, ["/Developer/Applications/Xcode.app"], expected_stdout=xcode_warning)