mirror of
https://github.com/facebook/sapling.git
synced 2024-10-06 14:58:03 +03:00
pretty print rage sections and normalize underlining
Summary: the rage summary is getting hard to quickly parse, so this underlines each section header, as well as unifies underline looks (with `eden stats`). This adopts the underline code from `eden du` and makes it a util function for shareability. Differential Revision: D30857773 fbshipit-source-id: 66b5b06f5b0125304d45d3465a8bc2248693b791
This commit is contained in:
parent
bae2745023
commit
21c2410a6d
@ -214,7 +214,7 @@ files outside the repo rather than to ignore and clean them up.\n""",
|
||||
backing_repos = set()
|
||||
all_redirections = set()
|
||||
|
||||
self.underlined("Mounts")
|
||||
self.write_ui(util.underlined("Mounts"))
|
||||
|
||||
# print all mounts together.
|
||||
for mount in mounts:
|
||||
@ -229,7 +229,7 @@ files outside the repo rather than to ignore and clean them up.\n""",
|
||||
|
||||
self.usage_for_mount(mount, args, clean, deep_clean)
|
||||
|
||||
self.underlined("Redirections")
|
||||
self.write_ui(util.underlined("Redirections"))
|
||||
|
||||
for mount in mounts:
|
||||
instance, checkout, _rel_path = require_checkout(args, mount)
|
||||
@ -249,7 +249,7 @@ parent of the buck-out directory.
|
||||
)
|
||||
|
||||
if backing_repos:
|
||||
self.underlined("Backing repos")
|
||||
self.write_ui(util.underlined("Backing repos"))
|
||||
for backing in backing_repos:
|
||||
self.writeln_ui(backing)
|
||||
|
||||
@ -310,7 +310,7 @@ space by running:
|
||||
return 0
|
||||
|
||||
def make_summary(self, clean, deep_clean):
|
||||
self.underlined("Summary")
|
||||
self.write_ui(util.underlined("Summary"))
|
||||
type_labels = {
|
||||
"materialized": "Materialized files",
|
||||
"redirection": "Redirections",
|
||||
@ -405,10 +405,6 @@ space by running:
|
||||
def writeln_ui(self, message, fg=None) -> None:
|
||||
self.write_ui(f"{message}\n")
|
||||
|
||||
def underlined(self, message) -> None:
|
||||
underline = "-" * len(message)
|
||||
self.write_ui(f"\n{message}\n{underline}\n")
|
||||
|
||||
def usage_for_dir(
|
||||
self, path, usage_type: str, print_label: Optional[str] = None
|
||||
) -> None:
|
||||
@ -442,7 +438,7 @@ space by running:
|
||||
def shared_usage(self, instance: EdenInstance, clean: bool) -> None:
|
||||
logs_dir = instance.state_dir / "logs"
|
||||
storage_dir = instance.state_dir / "storage"
|
||||
self.underlined("Shared space")
|
||||
self.write_ui(util.underlined("Shared space"))
|
||||
self.usage_for_dir(logs_dir, "shared")
|
||||
self.usage_for_dir(storage_dir, "shared")
|
||||
if clean:
|
||||
|
@ -25,15 +25,21 @@ from . import (
|
||||
redirect as redirect_mod,
|
||||
stats as stats_mod,
|
||||
ui as ui_mod,
|
||||
util as util_mod,
|
||||
version as version_mod,
|
||||
top as top_mod,
|
||||
)
|
||||
from .config import EdenInstance
|
||||
|
||||
|
||||
def section_title(message: str, out: IO[bytes]) -> None:
|
||||
out.write(util_mod.underlined(message).encode())
|
||||
|
||||
|
||||
def print_diagnostic_info(
|
||||
instance: EdenInstance, out: IO[bytes], dry_run: bool
|
||||
) -> None:
|
||||
section_title("System info:", out)
|
||||
header = (
|
||||
f"User : {getpass.getuser()}\n"
|
||||
f"Hostname : {socket.gethostname()}\n"
|
||||
@ -49,7 +55,7 @@ def print_diagnostic_info(
|
||||
|
||||
health_status = instance.check_health()
|
||||
if health_status.is_healthy():
|
||||
out.write(b"\n")
|
||||
section_title("Build info:", out)
|
||||
debug_mod.do_buildinfo(instance, out)
|
||||
out.write(b"uptime: ")
|
||||
instance.do_uptime(pretty=False, out=out)
|
||||
@ -69,7 +75,7 @@ def print_diagnostic_info(
|
||||
|
||||
print_eden_redirections(instance, out)
|
||||
|
||||
out.write(b"\nList of mount points:\n")
|
||||
section_title("List of mount points:", out)
|
||||
mountpoint_paths = []
|
||||
for key in sorted(instance.get_mount_paths()):
|
||||
out.write(key.encode() + b"\n")
|
||||
@ -139,10 +145,9 @@ def print_eden_doctor_report(instance: EdenInstance, out: IO[bytes]) -> None:
|
||||
doctor_rc = doctor_mod.cure_what_ails_you(
|
||||
instance, dry_run=True, out=ui_mod.PlainOutput(doctor_output)
|
||||
)
|
||||
out.write(
|
||||
b"\neden doctor --dry-run (exit code %d):\n%s\n"
|
||||
% (doctor_rc, doctor_output.getvalue().encode())
|
||||
)
|
||||
doctor_report_title = f"eden doctor --dry-run (exit code {doctor_rc}):"
|
||||
section_title(doctor_report_title, out)
|
||||
out.write(doctor_output.getvalue().encode())
|
||||
except Exception:
|
||||
out.write(b"\nUnexpected exception thrown while running eden doctor checks:\n")
|
||||
out.write(traceback.format_exc().encode("utf-8") + b"\n")
|
||||
@ -198,18 +203,19 @@ def print_expanded_log_file(path: Path, processor: str, out: IO[bytes]) -> None:
|
||||
pattern = re.compile("^.*\\n[a-zA-Z0-9_.-]*: .*\\n$")
|
||||
match = pattern.match(stdout)
|
||||
|
||||
section_title("Verbose EdenFS logs:", out)
|
||||
if not match:
|
||||
out.write(b"Verbose EdenFS logs: %s\n" % stdout.encode())
|
||||
out.write(stdout.encode())
|
||||
else:
|
||||
paste, _ = stdout.split("\n")[1].split(": ")
|
||||
out.write(b"Verbose EdenFS logs: %s\n" % paste.encode())
|
||||
out.write(paste.encode())
|
||||
except Exception as e:
|
||||
out.write(b"Error generating expanded EdenFS logs: %s\n" % str(e).encode())
|
||||
|
||||
|
||||
def print_tail_of_log_file(path: Path, out: IO[bytes]) -> None:
|
||||
try:
|
||||
out.write(b"\nMost recent EdenFS logs:\n")
|
||||
section_title("Most recent EdenFS logs:", out)
|
||||
LOG_AMOUNT = 20 * 1024
|
||||
with path.open("rb") as logfile:
|
||||
size = logfile.seek(0, io.SEEK_END)
|
||||
@ -247,7 +253,7 @@ def _get_running_eden_process_windows() -> List[Tuple[str, str, str, str, str, s
|
||||
|
||||
def print_running_eden_process(out: IO[bytes]) -> None:
|
||||
try:
|
||||
out.write(b"\nList of running EdenFS processes:\n")
|
||||
section_title("List of running EdenFS processes:", out)
|
||||
if sys.platform == "win32":
|
||||
lines = _get_running_eden_process_windows()
|
||||
else:
|
||||
@ -279,7 +285,7 @@ def print_edenfs_process_tree(pid: int, out: IO[bytes]) -> None:
|
||||
if sys.platform != "linux":
|
||||
return
|
||||
try:
|
||||
out.write(b"\nedenfs process tree:\n")
|
||||
section_title("EdenFS process tree:", out)
|
||||
output = subprocess.check_output(["ps", "-o", "sid=", "-p", str(pid)])
|
||||
sid = output.decode("utf-8").strip()
|
||||
output = subprocess.check_output(
|
||||
@ -295,7 +301,7 @@ def print_eden_redirections(instance: EdenInstance, out: IO[bytes]) -> None:
|
||||
# TODO(zeyi): fix this once eden redirect is working on Windows
|
||||
return
|
||||
try:
|
||||
out.write(b"\nedenfs redirections:\n")
|
||||
section_title("EdenFS redirections:", out)
|
||||
checkouts = instance.get_checkouts()
|
||||
for checkout in checkouts:
|
||||
out.write(bytes(checkout.path) + b"\n")
|
||||
@ -304,24 +310,24 @@ def print_eden_redirections(instance: EdenInstance, out: IO[bytes]) -> None:
|
||||
output = output.replace("\n", "\n\t")
|
||||
out.write(b"\t" + output.encode() + b"\n")
|
||||
except Exception as e:
|
||||
out.write(b"Error getting edenfs redirections %s\n" % str(e).encode())
|
||||
out.write(b"Error getting EdenFS redirections %s\n" % str(e).encode())
|
||||
out.write(traceback.format_exc().encode() + b"\n")
|
||||
|
||||
|
||||
def print_thrift_counters(instance: EdenInstance, out: IO[bytes]) -> None:
|
||||
try:
|
||||
out.write(b"\nedenfs counters:\n")
|
||||
out.write(util_mod.underlined("EdenFS counters:").encode())
|
||||
with instance.get_thrift_client_legacy() as client:
|
||||
counters = client.getRegexCounters(top_mod.COUNTER_REGEX)
|
||||
for key, value in counters.items():
|
||||
out.write(f"{key}: {value}\n".encode())
|
||||
except Exception as e:
|
||||
out.write(b"Error getting edenfs Thrift counters: %s\n" % str(e).encode())
|
||||
out.write(b"Error getting EdenFS Thrift counters: %s\n" % str(e).encode())
|
||||
|
||||
|
||||
def print_env_variables(out: IO[bytes]) -> None:
|
||||
try:
|
||||
out.write(b"\nEnvironment Variables:\n")
|
||||
section_title("Environment variables:", out)
|
||||
for k, v in os.environ.items():
|
||||
out.write(f"{k}={v}\n".encode())
|
||||
except Exception as e:
|
||||
@ -330,7 +336,7 @@ def print_env_variables(out: IO[bytes]) -> None:
|
||||
|
||||
def print_eden_config(instance: EdenInstance, out: IO[bytes]) -> None:
|
||||
try:
|
||||
out.write(b"\nedenfs config:\n")
|
||||
section_title("EdenFS config:", out)
|
||||
instance.print_full_config(out)
|
||||
except Exception as e:
|
||||
out.write(f"Error printing edenfs config: {e}\n".encode())
|
||||
out.write(f"Error printing EdenFS config: {e}\n".encode())
|
||||
|
@ -21,7 +21,7 @@ from facebook.eden.ttypes import GetStatInfoParams
|
||||
from thrift.protocol.TSimpleJSONProtocol import TSimpleJSONProtocolFactory
|
||||
from thrift.util import Serializer as ThriftSerializer
|
||||
|
||||
from . import cmd_util, stats_print, subcmd as subcmd_mod
|
||||
from . import cmd_util, stats_print, subcmd as subcmd_mod, util as util_mod
|
||||
from .config import EdenInstance
|
||||
from .subcmd import Subcmd
|
||||
|
||||
@ -82,28 +82,13 @@ def print_stats(stat_info, out: io.TextIOWrapper):
|
||||
blob_cache_size = None
|
||||
blob_cache_entry_count = None
|
||||
|
||||
out.write(
|
||||
textwrap.dedent(
|
||||
f"""\
|
||||
edenfs memory usage
|
||||
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
|
||||
private bytes: {private_bytes} ({resident_bytes} resident)
|
||||
"""
|
||||
)
|
||||
)
|
||||
out.write(util_mod.underlined("EdenFS memory usage:"))
|
||||
out.write(f"private bytes: {private_bytes} ({resident_bytes} resident)\n")
|
||||
|
||||
if blob_cache_size is not None and blob_cache_entry_count is not None:
|
||||
out.write(f"blob cache: {blob_cache_size} in {blob_cache_entry_count} blobs\n")
|
||||
|
||||
out.write(
|
||||
textwrap.dedent(
|
||||
f"""\
|
||||
|
||||
active mounts
|
||||
▔▔▔▔▔▔▔▔▔▔▔▔▔
|
||||
"""
|
||||
)
|
||||
)
|
||||
out.write(util_mod.underlined("active mounts:"))
|
||||
|
||||
inode_info = stat_info.mountPointInfo
|
||||
for key in inode_info:
|
||||
|
@ -669,6 +669,11 @@ def format_mount(mount) -> str:
|
||||
return os.fsdecode(os.path.basename(mount))
|
||||
|
||||
|
||||
def underlined(message: str) -> str:
|
||||
line = "-" * len(message)
|
||||
return f"\n{message}\n{line}\n"
|
||||
|
||||
|
||||
def is_edenfs_mount_device(device: bytes) -> bool:
|
||||
return device == b"edenfs" or device.startswith(b"edenfs:")
|
||||
|
||||
|
@ -26,7 +26,7 @@ class RageTest(testcase.EdenRepoTest):
|
||||
self.assertRegex(output, r"\nbuild_package_version\s*:")
|
||||
self.assertRegex(output, r"\nuptime\s*:")
|
||||
self.assertIn(f"\nChecking {self.mount}\n", output)
|
||||
self.assertIn("edenfs memory usage", output)
|
||||
self.assertIn("EdenFS memory usage", output)
|
||||
|
||||
def test_rage_output_with_stopped_daemon(self) -> None:
|
||||
self.eden.shutdown()
|
||||
@ -41,7 +41,7 @@ class RageTest(testcase.EdenRepoTest):
|
||||
# We may need to update this in the future if we modify the rage output; the
|
||||
# main purpose it simply to make sure that the rage command did not exit early
|
||||
# or crash partway through the output.
|
||||
self.assertRegex(output, r"^User\s*:")
|
||||
self.assertRegex(output, r"\nUser\s*:")
|
||||
self.assertRegex(output, r"\nHostname\s*:")
|
||||
self.assertRegex(output, r"\nVersion\s*:")
|
||||
self.assertIn("\neden doctor --dry-run", output)
|
||||
@ -49,4 +49,6 @@ class RageTest(testcase.EdenRepoTest):
|
||||
self.assertIn("\nList of running EdenFS processes:\n", output)
|
||||
self.assertIn("\nList of mount points:\n", output)
|
||||
self.assertIn(f"\nMount point info for path {self.mount}:\n", output)
|
||||
self.assertIn("\nEnvironment variables:\n", output)
|
||||
self.assertIn("\nEdenFS config:\n", output)
|
||||
self.assertIn(f"{self.mount}\n", output)
|
||||
|
Loading…
Reference in New Issue
Block a user