mirror of
https://github.com/facebook/sapling.git
synced 2024-10-10 08:47:12 +03:00
0b93429dc1
Summary: D21316793 is blocked from landing because there are a few targets in eden that are running pyre via buck targets integration. We can't do custom version overrides for projects that are using a mix of local configurations and buck integration, because buck doesn't provide an interface for setting the equivalent pyre version override. We're moving away from buck targets integration for pyre across the board, and I've run a codemod over the project to clean up all of the buck typing integration (including some residual mypy) as well as updated type ignores / fixmes accordingly. Let me know if you have any concerns; upon skimming it looks like most changes are either converting `type: ignore`s into fixmes, or removing `type: ignores`. Reviewed By: dkgi Differential Revision: D21343093 fbshipit-source-id: 5ee1436377eb526c0a679fb821c42e07cbca52a5
211 lines
5.8 KiB
Python
211 lines
5.8 KiB
Python
#!/usr/bin/env python3
|
|
# Copyright (c) Facebook, Inc. and its affiliates.
|
|
#
|
|
# This software may be used and distributed according to the terms of the
|
|
# GNU General Public License version 2.
|
|
|
|
import abc
|
|
import enum
|
|
import sys
|
|
from typing import BinaryIO, Dict, Optional, TextIO, Tuple
|
|
|
|
|
|
class Color(enum.Enum):
|
|
RED = enum.auto()
|
|
GREEN = enum.auto()
|
|
YELLOW = enum.auto()
|
|
|
|
|
|
class Attribute(enum.IntFlag):
|
|
BOLD = 0x01
|
|
UNDERLINE = 0x02
|
|
|
|
|
|
class Output(abc.ABC):
|
|
RED = Color.RED
|
|
GREEN = Color.GREEN
|
|
YELLOW = Color.YELLOW
|
|
BOLD = Attribute.BOLD
|
|
|
|
def writeln(
|
|
self,
|
|
msg: str,
|
|
fg: Optional[Color] = None,
|
|
bg: Optional[Color] = None,
|
|
attr: Optional[Attribute] = None,
|
|
flush: bool = False,
|
|
) -> None:
|
|
self.write(msg, fg=fg, bg=bg, attr=attr, end="\n", flush=flush)
|
|
|
|
@abc.abstractmethod
|
|
def write(
|
|
self,
|
|
msg: str,
|
|
fg: Optional[Color] = None,
|
|
bg: Optional[Color] = None,
|
|
attr: Optional[Attribute] = None,
|
|
end: Optional[str] = None,
|
|
flush: bool = False,
|
|
) -> None:
|
|
pass
|
|
|
|
|
|
class PlainOutput(Output):
|
|
def __init__(self, io: TextIO) -> None:
|
|
self.io = io
|
|
|
|
def write(
|
|
self,
|
|
msg: str,
|
|
fg: Optional[Color] = None,
|
|
bg: Optional[Color] = None,
|
|
attr: Optional[Attribute] = None,
|
|
end: Optional[str] = None,
|
|
flush: bool = False,
|
|
) -> None:
|
|
self.io.write(msg)
|
|
if end:
|
|
self.io.write(end)
|
|
if flush:
|
|
self.io.flush()
|
|
|
|
|
|
_term_settings: Optional["TerminalSettings"] = None
|
|
|
|
|
|
class TerminalSettings:
|
|
def __init__(
|
|
self,
|
|
foreground: Dict[Color, bytes],
|
|
background: Dict[Color, bytes],
|
|
attributes: Dict[Attribute, bytes],
|
|
reset: bytes,
|
|
) -> None:
|
|
self._foreground = foreground
|
|
self._background = background
|
|
self._attributes = attributes
|
|
self._reset = reset
|
|
|
|
@staticmethod
|
|
def getinstance() -> "TerminalSettings":
|
|
"""Get the TerminalSettings singleton object for this programs TTY.
|
|
|
|
This function calls curses.setupterm() to initialize the terminal the first time
|
|
it is called. Subsequent calls return the previously looked up terminal
|
|
information.
|
|
"""
|
|
global _term_settings
|
|
if _term_settings is not None:
|
|
# pyre-fixme[7]: Expected `TerminalSettings` but got
|
|
# `Optional[TerminalSettings]`.
|
|
return _term_settings
|
|
|
|
import curses
|
|
|
|
curses.setupterm()
|
|
|
|
set_foreground = curses.tigetstr("setaf") or b""
|
|
foreground = {
|
|
Color.RED: curses.tparm(set_foreground, curses.COLOR_RED),
|
|
Color.GREEN: curses.tparm(set_foreground, curses.COLOR_GREEN),
|
|
Color.YELLOW: curses.tparm(set_foreground, curses.COLOR_YELLOW),
|
|
}
|
|
|
|
set_background = curses.tigetstr("setab") or b""
|
|
background = {
|
|
Color.RED: curses.tparm(set_background, curses.COLOR_RED),
|
|
Color.GREEN: curses.tparm(set_background, curses.COLOR_GREEN),
|
|
Color.YELLOW: curses.tparm(set_background, curses.COLOR_YELLOW),
|
|
}
|
|
|
|
attributes = {
|
|
Attribute.BOLD: curses.tigetstr("bold") or b"",
|
|
Attribute.UNDERLINE: curses.tigetstr("smul") or b"",
|
|
}
|
|
|
|
reset = curses.tigetstr("sgr0") or b""
|
|
|
|
_term_settings = TerminalSettings(
|
|
foreground=foreground,
|
|
background=background,
|
|
attributes=attributes,
|
|
reset=reset,
|
|
)
|
|
# pyre-fixme[7]: Expected `TerminalSettings` but got
|
|
# `Optional[TerminalSettings]`.
|
|
return _term_settings
|
|
|
|
def get_attr_codes(
|
|
self,
|
|
fg: Optional[Color] = None,
|
|
bg: Optional[Color] = None,
|
|
attr: Optional[Attribute] = None,
|
|
) -> Tuple[bytes, bytes]:
|
|
start = b""
|
|
if fg:
|
|
start += self._foreground[fg]
|
|
if bg:
|
|
start += self._background[bg]
|
|
if attr:
|
|
for attr_type in Attribute:
|
|
if attr & int(attr_type):
|
|
start += self._attributes[attr_type]
|
|
|
|
if not start:
|
|
return (b"", b"")
|
|
return (start, self._reset)
|
|
|
|
|
|
class TerminalOutput(Output):
|
|
def __init__(
|
|
self, io: BinaryIO, term_settings: TerminalSettings, encoding: str = "utf-8"
|
|
) -> None:
|
|
self.io = io
|
|
self.term_settings = term_settings
|
|
self.encoding = encoding
|
|
self.encode_error = "replace"
|
|
|
|
def write(
|
|
self,
|
|
msg: str,
|
|
fg: Optional[Color] = None,
|
|
bg: Optional[Color] = None,
|
|
attr: Optional[Attribute] = None,
|
|
end: Optional[str] = None,
|
|
flush: bool = False,
|
|
) -> None:
|
|
start_str, end_str = self.term_settings.get_attr_codes(fg=fg, bg=bg, attr=attr)
|
|
|
|
self.io.write(start_str)
|
|
self.io.write(msg.encode(self.encoding, errors=self.encode_error))
|
|
self.io.write(end_str)
|
|
if end:
|
|
self.io.write(end.encode(self.encoding, errors=self.encode_error))
|
|
if flush:
|
|
self.io.flush()
|
|
|
|
|
|
def get_output(io: Optional[TextIO] = None) -> Output:
|
|
if io is None:
|
|
io = sys.stdout
|
|
if not io.isatty():
|
|
return PlainOutput(io)
|
|
io_buffer = getattr(io, "buffer", None)
|
|
if io_buffer is None:
|
|
return PlainOutput(io)
|
|
|
|
if sys.platform == "win32":
|
|
from . import win_ui
|
|
|
|
return win_ui.WindowsOutput(io)
|
|
|
|
import curses
|
|
|
|
try:
|
|
encoding = getattr(io, "encoding", "utf-8")
|
|
return TerminalOutput(io_buffer, TerminalSettings.getinstance(), encoding)
|
|
except curses.error:
|
|
# If curses fails for any reason (most likely the user has a broken terminal
|
|
# setting or terminfo database) fall back to the plain output.
|
|
return PlainOutput(io)
|