[ADD] guide de connexion : les outils posés, et ce que NixOS change
On entrait en ssh sans savoir que nix, PyCharm ou la forge étaient là, ni par quelle commande s'en servir : le guide ne connaissait que la distribution, ERPLibre et la présence d'un bureau. La liste vient du menu FILTRÉE par la machine — Android Studio n'existe qu'en x86_64, PyCharm veut un bureau — et chaque ligne est confrontée au code qui l'installe. Le bloc NixOS porte la racine du dépôt, seule ligne qui n'était ni absolue ni commande, et trois lignes qu'on ne devine pas : « --rollback », qui défait une déclaration fautive ; « nixos-version » ; et « ls /bin », vide alors que /bin/bash s'exécute. Une recherche de paquet a été essayée puis écartée, muette sur cette image. --- EN --- One logged in over ssh with no way to know nix, PyCharm or the forge were there, nor which command to use: the guide knew only the distribution, ERPLibre and whether a desktop was installed. The list comes from the menu FILTERED by the machine — Android Studio is x86_64 only, PyCharm wants a desktop — and every line is checked against the code that installs it. The NixOS block carries the checkout root, its only line neither absolute nor a command, and three lines nobody guesses: « --rollback », which undoes a faulty declaration; « nixos-version »; and « ls /bin », empty while /bin/bash runs. A package search was tried then dropped, silent on this image. Assisted-by: Claude Opus 5
This commit is contained in:
parent
7c8e4a6ffc
commit
1f5bdceb2a
3 changed files with 490 additions and 11 deletions
|
|
@ -2351,30 +2351,270 @@ AUR_GUIDE: tuple[tuple[str, str, str], ...] = (
|
|||
# « systemctl cat » plutôt qu'une ligne disant de ne pas faire : l'unité est
|
||||
# un lien vers le store, et la voir une fois dit mieux que toute explication
|
||||
# pourquoi « systemctl enable » n'a rien à faire ici.
|
||||
#
|
||||
# « --rollback » est ce qui rend l'édition SÛRE, et ne se devine pas : une
|
||||
# déclaration fautive se défait par une commande, là où les autres
|
||||
# distributions laissent un système à réparer à la main.
|
||||
#
|
||||
# « ls /bin » est le piège inverse d'une commande utile — il rend VIDE, et
|
||||
# pourtant /bin/bash s'exécute. envfs résout un nom à la demande sans jamais
|
||||
# énumérer, donc tout ce qui cherche par motif ne trouve rien, quand le nom
|
||||
# exact marche. Le Makefile tient par là (« SHELL := /bin/bash »), et une
|
||||
# sonde écrite en glob conclut à tort que l'interpréteur manque.
|
||||
#
|
||||
# Ce que ce bloc ne reprend PAS : nix-shell, nixos-rebuild switch et
|
||||
# nix-collect-garbage sont déjà dans le bloc du gestionnaire de paquets, qui
|
||||
# dit comment poser un logiciel. Ici on ne parle que de ce qu'ERPLibre change
|
||||
# à NixOS, et de ce que NixOS change à ERPLibre.
|
||||
NIXOS_GUIDE: tuple[tuple[str, str, str], ...] = (
|
||||
(
|
||||
"conf/nixos/erplibre.nix",
|
||||
"la déclaration d'ERPLibre, dans le dépôt",
|
||||
"ERPLibre's declaration, in the repository",
|
||||
"{el_dir}/conf/nixos/erplibre.nix",
|
||||
"la déclaration, dans le dépôt",
|
||||
"the declaration, in the checkout",
|
||||
),
|
||||
(
|
||||
"/etc/nixos/erplibre.nix",
|
||||
"sa copie — RÉÉCRITE par make install_os",
|
||||
"its copy — REWRITTEN by make install_os",
|
||||
"RÉÉCRITE par make install_os",
|
||||
"REWRITTEN by make install_os",
|
||||
),
|
||||
(
|
||||
"/etc/nixos/configuration.nix",
|
||||
"vos déclarations à vous, qui restent",
|
||||
"your own declarations, which do stay",
|
||||
"make install_os n'y touche pas",
|
||||
"make install_os never touches it",
|
||||
),
|
||||
(
|
||||
"sudo nixos-rebuild switch --rollback",
|
||||
"revenir à la génération d'avant",
|
||||
"back to the previous generation",
|
||||
),
|
||||
(
|
||||
"nixos-version",
|
||||
"version du système",
|
||||
"the system version",
|
||||
),
|
||||
(
|
||||
"systemctl cat erplibre",
|
||||
"l'unité vient du store, pas de /etc",
|
||||
"the unit comes from the store, not /etc",
|
||||
"vient du store, pas de /etc",
|
||||
"from the store, not from /etc",
|
||||
),
|
||||
(
|
||||
"ls /bin",
|
||||
"vide ; envfs résout sans lister",
|
||||
"empty; envfs resolves, no list",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def nixos_rows(el_dir: str) -> tuple[tuple[str, str, str], ...]:
|
||||
"""Le guide NixOS, sa racine d'installation substituée.
|
||||
|
||||
Le chemin du dépôt est le SEUL du bloc à ne pas être absolu, et le guide
|
||||
est lu par quelqu'un qui vient d'entrer en ssh, donc posé dans son foyer.
|
||||
Un chemin relatif l'envoie chercher un fichier là où il n'est pas.
|
||||
"""
|
||||
return tuple(
|
||||
(cmd.replace("{el_dir}", el_dir or "~/git/erplibre"), fr, en)
|
||||
for cmd, fr, en in NIXOS_GUIDE
|
||||
)
|
||||
|
||||
|
||||
# Les outils posés DANS la VM, et les quelques commandes qu'on tape en
|
||||
# entrant. Une entrée par clé du catalogue de script/todo/qemu_install.py ;
|
||||
# un test garde que toute clé d'ici y existe, sans quoi le guide annoncerait
|
||||
# un outil que le menu ne sait pas poser.
|
||||
#
|
||||
# Le TITRE de bloc est celui du guide, et non le libellé du catalogue : le
|
||||
# second nomme une case de menu, en anglais, quand le premier est lu dans la
|
||||
# langue de la VM.
|
||||
#
|
||||
# CE QUI EST ÉCRIT ICI DOIT ÊTRE VRAI SUR LA MACHINE. Le guide est lu par
|
||||
# quelqu'un qui vient d'entrer en ssh et qui va TAPER ces lignes : une
|
||||
# commande absente envoie chercher un binaire qui n'existe pas, ce qui coûte
|
||||
# plus qu'un guide muet. Chaque ligne a été confrontée au code qui l'installe.
|
||||
#
|
||||
# « {el_dir} » est remplacé par la racine de l'installation, comme dans le
|
||||
# bloc ERPLibre.
|
||||
TOOL_GUIDE: dict[str, tuple[str, tuple[tuple[str, str, str], ...]]] = {
|
||||
# nix POSÉ SUR UNE AUTRE DISTRIBUTION, et non NixOS : il n'y a ici ni
|
||||
# /etc/nixos ni nixos-rebuild, et les lignes de NIXOS_GUIDE n'y valent
|
||||
# pas. « profile add » et non « install » : l'alias est déprécié depuis
|
||||
# nix 2.30, et l'installateur amont sert une version postérieure.
|
||||
"nixanywhere": (
|
||||
"nix + nixos-anywhere",
|
||||
(
|
||||
(
|
||||
"/etc/nix/nix.conf",
|
||||
"nix-command et flakes, activés",
|
||||
"nix-command and flakes, enabled",
|
||||
),
|
||||
(
|
||||
"nix shell nixpkgs#<paquet>",
|
||||
"essayer, le temps d'un shell",
|
||||
"try it, for one shell",
|
||||
),
|
||||
(
|
||||
"nix profile add nixpkgs#<paquet>",
|
||||
"l'ajouter à son profil",
|
||||
"add it to your profile",
|
||||
),
|
||||
(
|
||||
"nixos-anywhere -f .#<hôte> root@<cible>",
|
||||
"installer NixOS à distance",
|
||||
"install NixOS remotely",
|
||||
),
|
||||
),
|
||||
),
|
||||
"pycharm": (
|
||||
"PyCharm",
|
||||
(
|
||||
(
|
||||
"pycharm {el_dir}",
|
||||
"ouvrir le dépôt dans l'IDE",
|
||||
"open the checkout in the IDE",
|
||||
),
|
||||
(
|
||||
"make pycharm_configure",
|
||||
"rejouer exécutions et exclusions du .idea",
|
||||
"replay the .idea run configs and exclusions",
|
||||
),
|
||||
),
|
||||
),
|
||||
"android": (
|
||||
"Android Studio",
|
||||
(
|
||||
(
|
||||
"studio",
|
||||
"lancer Android Studio (alias : android-studio)",
|
||||
"start Android Studio (alias: android-studio)",
|
||||
),
|
||||
(
|
||||
"grep -cE 'vmx|svm' /proc/cpuinfo",
|
||||
"0 : pas de KVM imbriqué, l'émulateur ne tournera pas",
|
||||
"0: no nested KVM, the emulator will not run",
|
||||
),
|
||||
),
|
||||
),
|
||||
"avd": (
|
||||
"Émulateur Android",
|
||||
(
|
||||
(
|
||||
"~/android/emulator/emulator -avd erplibre",
|
||||
"ouvrir l'AVD (par ssh -XC)",
|
||||
"open the AVD (over ssh -XC)",
|
||||
),
|
||||
(
|
||||
"~/android/platform-tools/adb devices",
|
||||
"voir l'émulateur en marche",
|
||||
"see the running emulator",
|
||||
),
|
||||
(
|
||||
"id -nG | grep -w kvm",
|
||||
"groupe kvm, sinon pas d'émulateur",
|
||||
"kvm group, or no emulator",
|
||||
),
|
||||
),
|
||||
),
|
||||
"mobile": (
|
||||
"ERPLibre mobile",
|
||||
(
|
||||
(
|
||||
"cd {el_dir}/mobile/erplibre_home_mobile",
|
||||
"le dépôt de l'application mobile",
|
||||
"the mobile app checkout",
|
||||
),
|
||||
(
|
||||
"npm test",
|
||||
"rejouer les tests Vitest",
|
||||
"replay the Vitest tests",
|
||||
),
|
||||
(
|
||||
"npm start",
|
||||
"servir l'application sans Android ni émulateur",
|
||||
"serve the app without Android or emulator",
|
||||
),
|
||||
(
|
||||
"tail -40 ~/erplibre-mobile-build.log",
|
||||
"le journal détaillé de la compilation",
|
||||
"the detailed build log",
|
||||
),
|
||||
),
|
||||
),
|
||||
"forgejo": (
|
||||
"Forgejo",
|
||||
(
|
||||
(
|
||||
"http://<ip>:3000",
|
||||
"forge git, compte et mot de passe erplibre",
|
||||
"git forge, account and password erplibre",
|
||||
),
|
||||
(
|
||||
"sudo systemctl status forgejo",
|
||||
"état du service",
|
||||
"the service's state",
|
||||
),
|
||||
(
|
||||
"sudo journalctl -u forgejo -f",
|
||||
"suivre son journal",
|
||||
"follow its log",
|
||||
),
|
||||
),
|
||||
),
|
||||
"gnome_ext": (
|
||||
"Extensions GNOME",
|
||||
(
|
||||
(
|
||||
"extension-manager",
|
||||
"le gestionnaire d'extensions, sur le bureau",
|
||||
"the extension manager, on the desktop",
|
||||
),
|
||||
(
|
||||
"gnome-extensions enable <uuid>",
|
||||
"activer depuis le bureau",
|
||||
"enable from the desktop",
|
||||
),
|
||||
(
|
||||
"dbus-run-session -- gnome-extensions enable <uuid>",
|
||||
"activer depuis ssh",
|
||||
"enable over ssh",
|
||||
),
|
||||
),
|
||||
),
|
||||
"aidev": (
|
||||
"Outils d'IA",
|
||||
(
|
||||
("claude", "lancer l'agent de code", "start the coding agent"),
|
||||
(
|
||||
"ls ~/.claude/commands",
|
||||
"les commandes /commit et /todo_* posées",
|
||||
"the /commit and /todo_* commands installed",
|
||||
),
|
||||
(
|
||||
"rtk gain",
|
||||
"les tokens économisés jusqu'ici",
|
||||
"tokens saved so far",
|
||||
),
|
||||
(
|
||||
"starship --version",
|
||||
"l'invite du shell, accrochée au démarrage",
|
||||
"the shell prompt, hooked at startup",
|
||||
),
|
||||
),
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def tool_rows(cle: str, el_dir: str) -> tuple[str, tuple]:
|
||||
"""(libellé, lignes) d'un outil, sa racine d'installation substituée."""
|
||||
entree = TOOL_GUIDE.get(cle)
|
||||
if not entree:
|
||||
return "", ()
|
||||
libelle, lignes = entree
|
||||
return libelle, tuple(
|
||||
(cmd.replace("{el_dir}", el_dir or "~/git/erplibre"), fr, en)
|
||||
for cmd, fr, en in lignes
|
||||
)
|
||||
|
||||
|
||||
def zypper_guide(rolling: bool) -> tuple[tuple[str, str, str], ...]:
|
||||
"""Aide-mémoire zypper. `rolling` : Tumbleweed plutôt que Leap.
|
||||
|
||||
|
|
@ -2558,6 +2798,7 @@ def build_motd(
|
|||
el_make: str = "",
|
||||
editor: str = "",
|
||||
desktop: bool = False,
|
||||
tools: tuple = (),
|
||||
) -> str:
|
||||
"""Texte du /etc/motd de la VM. Fonction PURE : aucun I/O, donc testable.
|
||||
|
||||
|
|
@ -2591,15 +2832,28 @@ def build_motd(
|
|||
body.append("")
|
||||
el_rows = erplibre_guide(el_dir, el_make, editor)
|
||||
body += motd_block("ERPLibre", el_rows, lang, gloss_col(el_rows))
|
||||
# UN BLOC PAR OUTIL POSÉ, titré de son libellé. La liste vient de
|
||||
# l'appelant, filtrée par la machine : annoncer un outil que l'
|
||||
# architecture ou l'absence de bureau écarte enverrait chercher une
|
||||
# commande qui ne sera jamais là. L'ordre est celui de la table, pour que
|
||||
# deux VM au même équipement rendent le même guide.
|
||||
for cle in TOOL_GUIDE:
|
||||
if cle not in (tools or ()):
|
||||
continue
|
||||
libelle, lignes = tool_rows(cle, el_dir)
|
||||
if not lignes:
|
||||
continue
|
||||
body.append("")
|
||||
body += motd_block(libelle, lignes, lang, gloss_col(lignes))
|
||||
# Même règle que le bloc AUR : il ne paraît qu'avec une installation,
|
||||
# parce que c'est elle qui pose le module dont ces lignes parlent.
|
||||
if mgr == "nix" and el_dir:
|
||||
body.append("")
|
||||
body += motd_block(
|
||||
_pick(("NixOS — déclaratif", "NixOS — declarative"), lang),
|
||||
NIXOS_GUIDE,
|
||||
nixos_rows(el_dir),
|
||||
lang,
|
||||
gloss_col(NIXOS_GUIDE),
|
||||
gloss_col(nixos_rows(el_dir)),
|
||||
)
|
||||
if desktop:
|
||||
body.append("")
|
||||
|
|
@ -3340,6 +3594,9 @@ def guide_files(args: argparse.Namespace) -> list[tuple[str, str, str, str]]:
|
|||
args.erplibre_make,
|
||||
editor,
|
||||
bool(args.desktop),
|
||||
tuple(
|
||||
c.strip() for c in args.vm_tools.split(",") if c.strip()
|
||||
),
|
||||
),
|
||||
"",
|
||||
)
|
||||
|
|
@ -4940,6 +5197,14 @@ def build_parser() -> argparse.ArgumentParser:
|
|||
"permet. Les paquets GNOME sont posés par la commande d'installation, "
|
||||
"pas ici.",
|
||||
)
|
||||
g_vm.add_argument(
|
||||
"--vm-tools",
|
||||
default="",
|
||||
help="Clés des outils que la commande d'installation va poser, "
|
||||
"séparées par des virgules. Ils ne sont PAS installés ici : la liste "
|
||||
"ne sert qu'au guide de connexion, qui les annonce et donne les "
|
||||
"quelques commandes dont on a besoin en entrant.",
|
||||
)
|
||||
g_vm.add_argument(
|
||||
"--gpu",
|
||||
choices=("auto", "on", "off"),
|
||||
|
|
|
|||
|
|
@ -1286,6 +1286,15 @@ class QemuDeployMixin:
|
|||
# ici plutôt qu'au petit bonheur, sinon l'installation se termine sur un
|
||||
# disque plein après une heure.
|
||||
extra += self._qemu_tools_disk_gb(vm_tools, arch, desktop, d)
|
||||
# Ce que le guide de connexion annoncera. FILTRÉ par la machine, et
|
||||
# non la liste cochée pour le parc : Android Studio n'existe qu'en
|
||||
# x86_64 et les extensions GNOME n'ont pas de sens sans bureau —
|
||||
# annoncer un outil qui ne sera pas posé enverrait chercher une
|
||||
# commande absente. Rien n'est installé par deploy_qemu.py, qui ne
|
||||
# s'en sert que pour écrire /etc/motd.
|
||||
retenus = self._qemu_tools_for(vm_tools, arch, desktop, d)
|
||||
if retenus:
|
||||
parts += ["--vm-tools", ",".join(retenus)]
|
||||
# TOUJOURS, même sans supplément : sans le drapeau, deploy_qemu.py
|
||||
# reprend la taille par défaut du catalogue. Une VM réglée à 60 G mais
|
||||
# sans rien à installer repartait donc à 20 G, en silence.
|
||||
|
|
|
|||
|
|
@ -461,5 +461,210 @@ class LeGuideNixosSeVoitEtDitVrai(unittest.TestCase):
|
|||
self.assertIn("services.openssh.settings.PrintMotd = true;", module)
|
||||
|
||||
|
||||
class LeCheminDuDepotEstEntierDansLeGuide(unittest.TestCase):
|
||||
"""Le guide est lu par quelqu'un qui vient d'entrer en ssh, donc posé
|
||||
dans son foyer, et qui va TAPER ce qu'il lit.
|
||||
|
||||
« conf/nixos/erplibre.nix » était la seule ligne du bloc à n'être ni un
|
||||
chemin absolu ni une commande : depuis le foyer elle ne désigne rien, et
|
||||
la racine change avec le profil — ~/git/erplibre en développement,
|
||||
/opt/erplibre en production. Elle porte donc la racine, comme les autres
|
||||
blocs le font déjà pour les leurs.
|
||||
"""
|
||||
|
||||
def _lignes(self, el_dir="~/git/erplibre"):
|
||||
return dq.nixos_rows(el_dir)
|
||||
|
||||
def test_the_checkout_path_is_complete(self):
|
||||
chemins = [c for c, _, _ in self._lignes() if "conf/nixos" in c]
|
||||
self.assertEqual(len(chemins), 1)
|
||||
self.assertTrue(chemins[0].startswith("~/git/erplibre/"), chemins[0])
|
||||
|
||||
def test_the_root_follows_the_profile(self):
|
||||
"""Écrire « ~/git/erplibre » en dur enverrait une machine de
|
||||
production chercher un dépôt qui n'y est pas."""
|
||||
chemins = [
|
||||
c for c, _, _ in self._lignes("/opt/erplibre") if "conf/nixos" in c
|
||||
]
|
||||
self.assertEqual(chemins, ["/opt/erplibre/conf/nixos/erplibre.nix"])
|
||||
|
||||
def test_a_missing_root_falls_back_rather_than_breaking(self):
|
||||
"""Un marqueur non substitué serait affiché tel quel."""
|
||||
rendu = "\n".join(c for c, _, _ in self._lignes(""))
|
||||
self.assertNotIn("{el_dir}", rendu)
|
||||
self.assertIn("~/git/erplibre/conf/nixos/erplibre.nix", rendu)
|
||||
|
||||
def test_no_line_is_a_bare_relative_path(self):
|
||||
"""La règle que la ligne fautive violait, sur TOUTES les lignes : ce
|
||||
qui n'est pas une commande est un chemin qu'on peut ouvrir d'où l'on
|
||||
est."""
|
||||
for cmd, _, _ in self._lignes():
|
||||
with self.subTest(cmd=cmd):
|
||||
if "/" not in cmd or " " in cmd:
|
||||
continue # une commande, pas un chemin
|
||||
self.assertTrue(
|
||||
cmd.startswith(("/", "~/")),
|
||||
f"{cmd} ne s'ouvre pas depuis le foyer",
|
||||
)
|
||||
|
||||
|
||||
class LeGuideNixosDitCeQueNixosChange(unittest.TestCase):
|
||||
"""Ce que le bloc ajoute, et qui ne se devine pas.
|
||||
|
||||
Chaque ligne a été confrontée à une VM NixOS 25.11 vivante avant d'être
|
||||
écrite : « nixos-version » rend bien sa version, « --rollback » est dans
|
||||
le synopsis de nixos-rebuild, et « ls /bin » rend VIDE sur une machine où
|
||||
/bin/bash s'exécute.
|
||||
|
||||
Une recherche de paquet a été ESSAYÉE puis écartée : « nix-env -qaP »
|
||||
ne rend rien sur cette image, dont le canal n'est pas peuplé, et
|
||||
« nix search » se met à tirer un canal entier. Un guide qui envoie taper
|
||||
une commande muette coûte plus qu'un guide qui se tait.
|
||||
"""
|
||||
|
||||
def _motd(self, **kw):
|
||||
return dq.build_motd(
|
||||
"nixos", "25.11", "amd64", el_dir="~/git/erplibre", **kw
|
||||
)
|
||||
|
||||
def test_the_safety_net_of_editing_is_named(self):
|
||||
"""Une déclaration fautive se défait par une commande ; ailleurs elle
|
||||
laisse un système à réparer à la main."""
|
||||
self.assertIn("nixos-rebuild switch --rollback", self._motd())
|
||||
|
||||
def test_the_version_is_reachable(self):
|
||||
self.assertIn("nixos-version", self._motd())
|
||||
|
||||
def test_the_trap_of_an_empty_bin_is_told(self):
|
||||
"""envfs résout un nom sans jamais énumérer : tout ce qui cherche par
|
||||
motif ne trouve rien, quand le nom exact marche."""
|
||||
motd = self._motd()
|
||||
self.assertIn("ls /bin", motd)
|
||||
self.assertIn("envfs", motd)
|
||||
|
||||
def test_it_does_not_repeat_the_package_block(self):
|
||||
"""nix-shell, « nixos-rebuild switch » nu et nix-collect-garbage sont
|
||||
déjà dans le bloc du gestionnaire de paquets. Les redire userait la
|
||||
seule chose que ce bloc a — dire ce qui n'est écrit nulle part."""
|
||||
commandes = [c for c, _, _ in dq.nixos_rows("~/git/erplibre")]
|
||||
for deja in (
|
||||
"nix-shell -p <paquet>",
|
||||
"sudo nixos-rebuild switch",
|
||||
"sudo nix-collect-garbage -d",
|
||||
):
|
||||
with self.subTest(commande=deja):
|
||||
self.assertNotIn(deja, commandes)
|
||||
|
||||
def test_both_languages_carry_every_line(self):
|
||||
"""Un bloc à moitié traduit se voit tout de suite, et fait douter du
|
||||
reste."""
|
||||
for _, fr, en in dq.nixos_rows("~/git/erplibre"):
|
||||
with self.subTest(fr=fr):
|
||||
self.assertTrue(fr.strip())
|
||||
self.assertTrue(en.strip())
|
||||
self.assertNotEqual(fr, en)
|
||||
|
||||
|
||||
class LesOutilsPosesSAnnoncent(unittest.TestCase):
|
||||
"""Le guide ne disait rien des outils installés dans la VM : on entrait
|
||||
en ssh sans savoir que nix, PyCharm ou la forge étaient là, ni par quelle
|
||||
commande s'en servir.
|
||||
|
||||
Ce qui est écrit doit être VRAI sur la machine : le lecteur va taper ces
|
||||
lignes, et une commande absente coûte plus qu'un guide muet.
|
||||
"""
|
||||
|
||||
def _motd(self, tools, **kw):
|
||||
return dq.build_motd(
|
||||
"ubuntu",
|
||||
"24.04",
|
||||
"amd64",
|
||||
el_dir="~/git/erplibre",
|
||||
tools=tools,
|
||||
**kw,
|
||||
)
|
||||
|
||||
def test_only_what_was_installed_is_announced(self):
|
||||
motd = self._motd(("pycharm",))
|
||||
self.assertIn("PyCharm", motd)
|
||||
self.assertNotIn("nixos-anywhere", motd)
|
||||
self.assertNotIn("Forgejo", motd)
|
||||
|
||||
def test_a_vm_without_tools_gains_nothing(self):
|
||||
"""Le cas ordinaire ne doit pas gagner de bloc vide."""
|
||||
motd = self._motd(())
|
||||
for libelle, _lignes in dq.TOOL_GUIDE.values():
|
||||
with self.subTest(libelle=libelle):
|
||||
self.assertNotIn(libelle, motd)
|
||||
|
||||
def test_the_checkout_root_is_substituted(self):
|
||||
"""« {el_dir} » laissé tel quel ferait taper une accolade."""
|
||||
motd = self._motd(("pycharm",), el_make="install_odoo_18")
|
||||
self.assertIn("pycharm ~/git/erplibre", motd)
|
||||
self.assertNotIn("{el_dir}", motd)
|
||||
|
||||
def test_nix_on_another_distribution_is_not_nixos(self):
|
||||
"""L'outil pose nix en démon SUR une distribution ordinaire : il n'y a
|
||||
ni /etc/nixos ni nixos-rebuild, et reprendre les lignes du bloc NixOS
|
||||
enverrait chercher des commandes qui n'existent pas ici."""
|
||||
motd = self._motd(("nixanywhere",))
|
||||
self.assertIn("nix shell nixpkgs#", motd)
|
||||
self.assertNotIn("nixos-rebuild", motd)
|
||||
self.assertNotIn("/etc/nixos", motd)
|
||||
|
||||
def test_the_deprecated_profile_verb_is_not_taught(self):
|
||||
"""« nix profile install » est un alias déprécié depuis nix 2.30, et
|
||||
l'installateur amont sert une version postérieure : le proposer ferait
|
||||
répondre un avertissement à qui le tape."""
|
||||
motd = self._motd(("nixanywhere",))
|
||||
self.assertIn("nix profile add", motd)
|
||||
self.assertNotIn("nix profile install", motd)
|
||||
|
||||
def test_every_key_exists_in_the_catalogue(self):
|
||||
"""Une clé d'ici que le menu ne sait pas poser annoncerait un outil
|
||||
qui n'arrivera jamais."""
|
||||
import sys
|
||||
|
||||
sys.argv = ["todo.py"]
|
||||
from script.todo.todo import TODO
|
||||
|
||||
for cle in dq.TOOL_GUIDE:
|
||||
with self.subTest(cle=cle):
|
||||
self.assertIn(cle, TODO._QEMU_VM_TOOLS)
|
||||
|
||||
def test_the_menu_hands_over_the_filtered_list(self):
|
||||
"""La liste cochée vaut pour le parc ; celle-ci est filtrée par la
|
||||
machine. Android Studio n'existe qu'en x86_64 et PyCharm veut un
|
||||
bureau — les annoncer ailleurs enverrait chercher une commande qui ne
|
||||
sera jamais posée."""
|
||||
import sys
|
||||
|
||||
sys.argv = ["todo.py"]
|
||||
from script.todo.todo import TODO
|
||||
|
||||
todo = TODO.__new__(TODO)
|
||||
choisis = ("nixanywhere", "pycharm", "android")
|
||||
|
||||
def parts(arch, desktop):
|
||||
p = todo._qemu_build_deploy_parts(
|
||||
"ubuntu",
|
||||
"24.04",
|
||||
arch,
|
||||
"vm",
|
||||
4096,
|
||||
2,
|
||||
"40G",
|
||||
None,
|
||||
"develop",
|
||||
desktop=desktop,
|
||||
vm_tools=choisis,
|
||||
dry_run=True,
|
||||
)
|
||||
return p[p.index("--vm-tools") + 1] if "--vm-tools" in p else ""
|
||||
|
||||
self.assertEqual("nixanywhere,pycharm,android", parts("amd64", True))
|
||||
self.assertEqual("nixanywhere", parts("arm64", False))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
Loading…
Reference in a new issue