refactor: prepare the interactive shell in its own module
driver / standard (pull_request) Successful in 40s
driver / lint (pull_request) Successful in 27s
driver / test (3.10) (pull_request) Successful in 3m57s
driver / test (3.11) (pull_request) Successful in 1m7s
driver / test (3.12) (pull_request) Successful in 1m9s
driver / types (pull_request) Successful in 19m18s
driver / lowest (pull_request) Successful in 43s
driver / security (pull_request) Successful in 1m3s
driver / build (pull_request) Successful in 58s
driver / test (3.13) (pull_request) Successful in 16m1s
CI / driver (pull_request) Successful in 23m9s
driver / publish (pull_request) Skipped
driver / standard (pull_request) Successful in 40s
driver / lint (pull_request) Successful in 27s
driver / test (3.10) (pull_request) Successful in 3m57s
driver / test (3.11) (pull_request) Successful in 1m7s
driver / test (3.12) (pull_request) Successful in 1m9s
driver / types (pull_request) Successful in 19m18s
driver / lowest (pull_request) Successful in 43s
driver / security (pull_request) Successful in 1m3s
driver / build (pull_request) Successful in 58s
driver / test (3.13) (pull_request) Successful in 16m1s
CI / driver (pull_request) Successful in 23m9s
driver / publish (pull_request) Skipped
The prompt-hook step (#41) pushed linux.py past its line count in the quality baseline. The three steps that make netmiko's fresh shell fit to read - history off, prompt hooks off, no line wrap - and the prompt pattern move to napalm_linux/_shell.py, under strict mypy. linux.py shrinks below where it was; the baseline follows.
This commit is contained in:
1 parent
4159612a33
commit
42e93f02dd
5 files changed
+66
-48
No files matched your search
@@ -0,0 +1,54 @@
|
||||
"""The interactive shell netmiko opens, made fit to be read before the first command."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
#: The end of a command's output when nothing better is known: a line that looks
|
||||
#: like a shell prompt.
|
||||
PROMPT_RE = r"[#$\>]\s*$"
|
||||
|
||||
#: Sent before anything else in the interactive session (NetOrk/netork#1039):
|
||||
#: the shell writes no history file and records nothing more. The leading space
|
||||
#: keeps this line itself out of a history under ``HISTCONTROL=ignorespace``;
|
||||
#: a shell without ``set -o history`` (dash) only complains, to /dev/null.
|
||||
HISTORY_OFF = " unset HISTFILE; set +o history 2>/dev/null; true"
|
||||
|
||||
#: Sent right after ``HISTORY_OFF`` (#41): systemd 258's
|
||||
#: ``/etc/profile.d/80-systemd-osc-context.sh`` wraps every command in OSC 3008
|
||||
#: sequences from ``PS0`` and ``PROMPT_COMMAND``, each with a fresh UUID. It appends
|
||||
#: to ``PROMPT_COMMAND`` as an array, so only ``unset`` removes its hook.
|
||||
PROMPT_HOOKS_OFF = " unset PS0 PROMPT_COMMAND; true"
|
||||
|
||||
#: Keeps the PTY from wrapping long output lines (e.g. docker JSON).
|
||||
NO_LINE_WRAP = "stty cols 10000 2>/dev/null || true"
|
||||
|
||||
|
||||
def prepare_shell(device: Any, hostname: str) -> None:
|
||||
"""Make netmiko's fresh shell *device* fit to read, one step at a time.
|
||||
|
||||
A step the shell refuses is logged and skipped: none of them is worth
|
||||
failing the connection for.
|
||||
"""
|
||||
# No history before anything else is typed (NetOrk/netork#1039).
|
||||
try:
|
||||
device.send_command(HISTORY_OFF, expect_string=PROMPT_RE)
|
||||
except Exception:
|
||||
logger.debug("Could not switch the shell history off on %s", hostname, exc_info=True)
|
||||
|
||||
# No systemd OSC 3008 context around every command (#41). netmiko learned
|
||||
# the prompt with those sequences in front, and a prompt carrying a fresh
|
||||
# UUID never matches again, so it reads the prompt anew once they are gone.
|
||||
try:
|
||||
device.send_command(PROMPT_HOOKS_OFF, expect_string=PROMPT_RE)
|
||||
device.set_base_prompt()
|
||||
except Exception:
|
||||
logger.debug("Could not switch the prompt hooks off on %s", hostname, exc_info=True)
|
||||
|
||||
try:
|
||||
device.send_command(NO_LINE_WRAP, expect_string=PROMPT_RE)
|
||||
except Exception:
|
||||
logger.debug("%s: ignored", hostname, exc_info=True)
|
||||
Reference in new issue
Block a user