erplibre/script/todo/ssh_config.py
Mathieu Benoit cfbdd9406e [REF] format : passer l'outillage et les tests sous ruff
Le formateur de ce dépôt est ruff depuis qu'il remplace black, qui ne connaît
aucune cible au-delà de py313 ; ce passage applique sa norme à l'arbre entier,
d'un coup, pour qu'aucun commit de fond n'ait à porter du style. L'écart tient
presque entièrement aux chaînes coupées à la main que ruff recolle quand elles
tiennent sur une ligne, et aux « with » multiples qu'il regroupe : aucune
valeur ne change, et les clés de traduction non plus.
Vérifié : la suite unitaire reste verte après le passage, et le contrôle de
syntaxe ne signale rien.

--- EN ---

This repository's formatter is ruff since it replaced black, which knows no
target beyond py313; this pass applies its standard to the whole tree at once,
so that no substantive commit has to carry style. The difference is almost
entirely the hand-split strings ruff joins back when they fit on one line, and
the multiple "with" it merges: no value changes, nor do the translation keys.
Checked: the unit suite stays green after the pass, and the syntax check
reports nothing.

Assisted-by: Claude Opus 5
2026-09-24 14:40:38 -04:00

52 lines
2.3 KiB
Python

#!/usr/bin/env python3
# © 2026 TechnoLibre (http://www.technolibre.ca)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
"""Ce qu'est un nom de machine dans ~/.ssh/config, décidé en un seul endroit.
Trois lecteurs de ce fichier vivent dans ce dépôt — l'énumération des alias,
le menu de montage qui veut aussi l'adresse, et l'inventaire des entrées de
VM — et ils divergeaient sur la MÊME question. L'un comparait le mot-clé avec
la casse, un autre exigeait un espace là où une tabulation est légale, un
troisième laissait passer le motif nié. Un alias déclaré `host exo` était donc
vu par l'un et invisible aux autres, ce qui se lit comme une panne
intermittente de la découverte.
Le module ne lit aucun fichier et ne suit pas `Include` : il tranche une
ligne, rien de plus. Un alias déclaré dans un fichier inclus reste donc
invisible aux trois lecteurs, alors même que `ssh -G` le résoudrait — la
source est incomplète sans être fausse.
"""
from __future__ import annotations
import re
# Le mot-clé, suivi d'au moins un blanc. ssh_config ne distingue pas la casse
# de ses mots-clés, et sépare par espace OU tabulation. Le blanc est exigé
# sans quoi `HostName` serait lu comme une déclaration d'hôte.
DECLARATION = re.compile(r"^[ \t]*host[ \t]+", re.IGNORECASE)
def declared_names(line) -> list | None:
"""Les noms de machine d'une ligne « Host », ou None si ce n'en est pas une.
Rend None pour toute autre ligne, et une liste — possiblement VIDE —
quand la ligne est une déclaration. Distinguer les deux compte : `Host *`
EST une déclaration qui ne nomme aucune machine, et un lecteur qui
accumule un bloc doit clore le précédent malgré tout. Rendre `[]` dans
les deux cas rattachait les directives d'un bloc générique au bloc
précédent.
Trois formes ne désignent aucune machine et sortent : les jokers `*` et
`?`, qui décrivent une règle appliquée à plusieurs hôtes, et le motif NIÉ
`!nom`, qui RETIRE un nom de l'ensemble que la ligne vient de décrire.
Retenir un motif nié rend une cible dont le nom commence par `!`, que ssh
ne résoudra jamais.
"""
if not DECLARATION.match(line or ""):
return None
return [
nom
for nom in line.split()[1:]
if "*" not in nom and "?" not in nom and not nom.startswith("!")
]