Files
scott c157e14fa9 Restructure into package: truenas_migrate/
Split single-file script into focused modules:
  colors.py   – ANSI helpers and shared logger
  summary.py  – Summary dataclass and report renderer
  archive.py  – Debug archive parser (SCALE + CORE layouts)
  client.py   – WebSocket engine, TrueNASClient, dataset utilities
  migrate.py  – Payload builders, migrate_smb_shares, migrate_nfs_shares
  cli.py      – Interactive wizard, argparse, run(), main()
  __main__.py – python -m truenas_migrate entry point

truenas_migrate.py retained as a one-line compatibility shim.
Both 'python truenas_migrate.py' and 'python -m truenas_migrate' work.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 21:50:00 -05:00

56 lines
1.8 KiB
Python

"""ANSI color helpers and shared logger."""
from __future__ import annotations
import logging
import re as _re
import sys
_USE_COLOR = sys.stderr.isatty()
def _c(code: str, text: str) -> str:
return f"\033[{code}m{text}\033[0m" if _USE_COLOR else text
def _dim(t: str) -> str: return _c("2", t)
def _bold(t: str) -> str: return _c("1", t)
def _red(t: str) -> str: return _c("31", t)
def _green(t: str) -> str: return _c("32", t)
def _yellow(t: str) -> str: return _c("33", t)
def _cyan(t: str) -> str: return _c("36", t)
def _bold_red(t: str) -> str: return _c("1;31", t)
def _bold_green(t: str) -> str: return _c("1;32", t)
def _bold_yellow(t: str) -> str: return _c("1;33", t)
def _bold_cyan(t: str) -> str: return _c("1;36", t)
def _vis_len(s: str) -> int:
"""Visible character width of a string, ignoring ANSI escape sequences."""
return len(_re.sub(r'\033\[[0-9;]*m', '', s))
class _ColorFormatter(logging.Formatter):
_STYLES = {
logging.DEBUG: "2",
logging.INFO: "36",
logging.WARNING: "1;33",
logging.ERROR: "1;31",
logging.CRITICAL: "1;31",
}
def format(self, record: logging.LogRecord) -> str:
ts = self.formatTime(record, self.datefmt)
msg = record.getMessage()
if _USE_COLOR:
code = self._STYLES.get(record.levelno, "0")
level = f"\033[{code}m{record.levelname:<8}\033[0m"
ts = f"\033[2m{ts}\033[0m"
else:
level = f"{record.levelname:<8}"
return f"{ts} {level} {msg}"
_handler = logging.StreamHandler()
_handler.setFormatter(_ColorFormatter(datefmt="%H:%M:%S"))
logging.basicConfig(level=logging.INFO, handlers=[_handler])
log = logging.getLogger("truenas_migrate")