| Index: third_party/typ/typ/host.py
|
| diff --git a/third_party/typ/typ/host.py b/third_party/typ/typ/host.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..5738e3a5883496ac0900ae235acb717563841a0b
|
| --- /dev/null
|
| +++ b/third_party/typ/typ/host.py
|
| @@ -0,0 +1,282 @@
|
| +# Copyright 2014 Dirk Pranke. All rights reserved.
|
| +#
|
| +# Licensed under the Apache License, Version 2.0 (the "License");
|
| +# you may not use this file except in compliance with the License.
|
| +# You may obtain a copy of the License at
|
| +#
|
| +# http://www.apache.org/licenses/LICENSE-2.0
|
| +#
|
| +# Unless required by applicable law or agreed to in writing, software
|
| +# distributed under the License is distributed on an "AS IS" BASIS,
|
| +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| +# See the License for the specific language governing permissions and
|
| +# limitations under the License.
|
| +
|
| +import io
|
| +import logging
|
| +import multiprocessing
|
| +import os
|
| +import shutil
|
| +import subprocess
|
| +import sys
|
| +import tempfile
|
| +import time
|
| +
|
| +
|
| +if sys.version_info.major == 2: # pragma: python2
|
| + from urllib2 import urlopen, Request
|
| +else: # pragma: python3
|
| + # pylint: disable=E0611
|
| + assert sys.version_info.major == 3
|
| + from urllib.request import urlopen, Request # pylint: disable=F0401,E0611
|
| +
|
| +
|
| +is_debugging = False
|
| +
|
| +
|
| +class Host(object):
|
| + python_interpreter = sys.executable
|
| + is_python3 = bool(sys.version_info.major == 3)
|
| +
|
| + sep = os.sep
|
| + env = os.environ
|
| +
|
| + _orig_stdout = sys.stdout
|
| + _orig_stderr = sys.stderr
|
| +
|
| + def __init__(self):
|
| + self.logger = logging.getLogger()
|
| + self._orig_logging_handlers = None
|
| + self.stdout = sys.stdout
|
| + self.stderr = sys.stderr
|
| + self.stdin = sys.stdin
|
| + self.env = os.environ
|
| +
|
| + def set_debugging(self, flag): # pragma: untested
|
| + # TODO: We currently use this to work around typ's brokenness
|
| + # when running -d under python3. We may or may not actually need
|
| + # this hook.
|
| + # pylint: disable=W0603
|
| + global is_debugging
|
| + is_debugging = flag
|
| +
|
| + def abspath(self, *comps):
|
| + return os.path.abspath(self.join(*comps))
|
| +
|
| + def add_to_path(self, *comps):
|
| + absolute_path = self.abspath(*comps)
|
| + if absolute_path not in sys.path:
|
| + sys.path.append(absolute_path)
|
| +
|
| + def basename(self, path):
|
| + return os.path.basename(path)
|
| +
|
| + def call(self, argv, stdin=None, env=None):
|
| + if stdin:
|
| + stdin_pipe = subprocess.PIPE
|
| + else:
|
| + stdin_pipe = None
|
| + proc = subprocess.Popen(argv, stdout=subprocess.PIPE,
|
| + stderr=subprocess.PIPE, stdin=stdin_pipe,
|
| + env=env)
|
| + if stdin_pipe:
|
| + proc.stdin.write(stdin.encode('utf-8'))
|
| + stdout, stderr = proc.communicate()
|
| +
|
| + # pylint type checking bug - pylint: disable=E1103
|
| + return proc.returncode, stdout.decode('utf-8'), stderr.decode('utf-8')
|
| +
|
| + def chdir(self, *comps):
|
| + return os.chdir(self.join(*comps))
|
| +
|
| + def cpu_count(self):
|
| + return multiprocessing.cpu_count()
|
| +
|
| + def dirname(self, *comps):
|
| + return os.path.dirname(self.join(*comps))
|
| +
|
| + def exists(self, *comps):
|
| + return os.path.exists(self.join(*comps))
|
| +
|
| + def files_under(self, top):
|
| + all_files = []
|
| + for root, _, files in os.walk(top):
|
| + for f in files:
|
| + relpath = self.relpath(os.path.join(root, f), top)
|
| + all_files.append(relpath)
|
| + return all_files
|
| +
|
| + def getcwd(self):
|
| + return os.getcwd()
|
| +
|
| + def getenv(self, key, default=None):
|
| + return self.env.get(key, default)
|
| +
|
| + def getpid(self):
|
| + return os.getpid()
|
| +
|
| + def for_mp(self):
|
| + return None
|
| +
|
| + def isdir(self, *comps):
|
| + return os.path.isdir(os.path.join(*comps))
|
| +
|
| + def isfile(self, *comps):
|
| + return os.path.isfile(os.path.join(*comps))
|
| +
|
| + def join(self, *comps):
|
| + return os.path.join(*comps)
|
| +
|
| + def maybe_mkdir(self, *comps):
|
| + path = self.abspath(self.join(*comps))
|
| + if not self.exists(path):
|
| + os.mkdir(path)
|
| +
|
| + def mkdtemp(self, **kwargs):
|
| + return tempfile.mkdtemp(**kwargs)
|
| +
|
| + def mtime(self, *comps):
|
| + return os.stat(self.join(*comps)).st_mtime
|
| +
|
| + def print_(self, msg='', end='\n', stream=None):
|
| + stream = stream or self.stdout
|
| + stream.write(str(msg) + end)
|
| + stream.flush()
|
| +
|
| + def read_text_file(self, *comps):
|
| + return self._read(comps, 'r')
|
| +
|
| + def read_binary_file(self, *comps):
|
| + return self._read(comps, 'rb')
|
| +
|
| + def _read(self, comps, mode):
|
| + path = self.join(*comps)
|
| + with open(path, mode) as f:
|
| + return f.read()
|
| +
|
| + def relpath(self, path, start):
|
| + return os.path.relpath(path, start)
|
| +
|
| + def remove(self, *comps):
|
| + os.remove(self.join(*comps))
|
| +
|
| + def rmtree(self, path):
|
| + shutil.rmtree(path, ignore_errors=True)
|
| +
|
| + def splitext(self, path):
|
| + return os.path.splitext(path)
|
| +
|
| + def time(self):
|
| + return time.time()
|
| +
|
| + def write_text_file(self, path, contents):
|
| + return self._write(path, contents, mode='w')
|
| +
|
| + def write_binary_file(self, path, contents):
|
| + return self._write(path, contents, mode='wb')
|
| +
|
| + def _write(self, path, contents, mode):
|
| + with open(path, mode) as f:
|
| + f.write(contents)
|
| +
|
| + def fetch(self, url, data=None, headers=None):
|
| + headers = headers or {}
|
| + return urlopen(Request(url, data.encode('utf8'), headers))
|
| +
|
| + def terminal_width(self):
|
| + """Returns 0 if the width cannot be determined."""
|
| + try:
|
| + if sys.platform == 'win32': # pragma: win32
|
| + # From http://code.activestate.com/recipes/ \
|
| + # 440694-determine-size-of-console-window-on-windows/
|
| + from ctypes import windll, create_string_buffer
|
| +
|
| + STDERR_HANDLE = -12
|
| + handle = windll.kernel32.GetStdHandle(STDERR_HANDLE)
|
| +
|
| + SCREEN_BUFFER_INFO_SZ = 22
|
| + buf = create_string_buffer(SCREEN_BUFFER_INFO_SZ)
|
| +
|
| + if windll.kernel32.GetConsoleScreenBufferInfo(handle, buf):
|
| + import struct
|
| + fields = struct.unpack("hhhhHhhhhhh", buf.raw)
|
| + left = fields[5]
|
| + right = fields[7]
|
| +
|
| + # Note that we return 1 less than the width since writing
|
| + # into the rightmost column automatically performs a
|
| + # line feed.
|
| + return right - left
|
| + return 0
|
| + else: # pragma: no win32
|
| + import fcntl
|
| + import struct
|
| + import termios
|
| + packed = fcntl.ioctl(self.stderr.fileno(),
|
| + termios.TIOCGWINSZ, '\0' * 8)
|
| + _, columns, _, _ = struct.unpack('HHHH', packed)
|
| + return columns
|
| + except Exception: # pragma: untested
|
| + return 0
|
| +
|
| + def _tap_output(self):
|
| + self.stdout = sys.stdout = _TeedStream(self.stdout)
|
| + self.stderr = sys.stderr = _TeedStream(self.stderr)
|
| +
|
| + def _untap_output(self):
|
| + assert isinstance(self.stdout, _TeedStream)
|
| + self.stdout = sys.stdout = self.stdout.stream
|
| + self.stderr = sys.stderr = self.stderr.stream
|
| +
|
| + def capture_output(self, divert=True):
|
| + self._tap_output()
|
| +
|
| + # TODO: Make log capture more robust.
|
| + self._orig_logging_handlers = self.logger.handlers
|
| + if self._orig_logging_handlers: # pragma: untested
|
| + self.logger.handlers = [logging.StreamHandler(self.stderr)]
|
| +
|
| + self.stdout.capture(divert)
|
| + self.stderr.capture(divert)
|
| +
|
| + def restore_output(self):
|
| + assert isinstance(self.stdout, _TeedStream)
|
| + out, err = (self.stdout.restore(), self.stderr.restore())
|
| + self.logger.handlers = self._orig_logging_handlers
|
| + self._untap_output()
|
| + return out, err
|
| +
|
| +
|
| +class _TeedStream(io.StringIO):
|
| +
|
| + def __init__(self, stream):
|
| + super(_TeedStream, self).__init__()
|
| + self.stream = stream
|
| + self.capturing = False
|
| + self.diverting = False
|
| +
|
| + def write(self, msg, *args, **kwargs): # pragma: untested
|
| + if self.capturing:
|
| + if sys.version_info.major == 2 and isinstance(msg, str):
|
| + msg = unicode(msg)
|
| + super(_TeedStream, self).write(msg, *args, **kwargs)
|
| + if not self.diverting:
|
| + self.stream.write(msg, *args, **kwargs)
|
| +
|
| + def flush(self): # pragma: untested
|
| + if self.capturing:
|
| + super(_TeedStream, self).flush()
|
| + if not self.diverting:
|
| + self.stream.flush()
|
| +
|
| + def capture(self, divert=True):
|
| + self.truncate(0)
|
| + self.capturing = True
|
| + self.diverting = divert
|
| +
|
| + def restore(self):
|
| + msg = self.getvalue()
|
| + self.truncate(0)
|
| + self.capturing = False
|
| + self.diverting = False
|
| + return msg
|
|
|