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>
56 lines
1.8 KiB
Python
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")
|