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
52 lines
2.3 KiB
Python
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("!")
|
|
]
|