class

Beryl::Apply::Primitive

Inherits Reference < Object

Tâche élémentaire idempotente exécutée sur l'hôte distant. Chaque primitive lit l'état réel via shell avant d'agir et retourne un StepResult. En dry_run, elle calcule le delta mais n'applique rien (Outcome::Applied annonce alors ce qui serait fait).

Constants

KILL_AFTER = 10

Commande service <svc> <action> qui ne retient PAS la session SSH : un script rc.d qui lance son démon sans fermer ses descripteurs (daemon(8) sans -f) lui transmet stdin/stdout de la session, et l'apply attend alors indéfiniment la fin d'un démon qui ne finit jamais (cas réel le 6 oct. 2026). Les descripteurs du démon pointent ici vers un fichier temporaire, relu ensuite : la sortie et le code de retour de service sont conservés. timeout (secondes) borne une action qui ne rend pas la main : timeout(1) du système de base sort alors en 124. --foreground : sans lui, timeout(1) de FreeBSD se fait « reaper » — le démon lancé par le rc.d reste son descendant, timeout attend sa fin (jamais) puis le TUE au bout du délai (loulou, 27 oct. 2026 : partiduo, partiduo_admin arrêtés par la relance censée les redémarrer). -k 10 : KILL si le rc.d ignore le TERM.

SHELL_ERROR_RE = /Unmatched ['"`]|Illegal variable name|Command not found|Syntax error|Bad substitution|Missing name for redirect|Undefined variable|parameter (null or )?not set/i

Messages d'erreur du shell lui-même (sh FreeBSD, et csh quand il lit la ligne — cas réel sur qwerty, 14 oct. 2026). Une sonde ou une garde légitime ne les produit pas en répondant « non ».

SHELL_FAILURE_CODES = {Apply::DECODE_FAILED, 126, 127}

Codes qui disent que le SHELL n'a pas pu jouer une commande, pas qu'elle répond « non » : décodage impossible (cf. Apply.sh_line), commande non exécutable, commande introuvable.

Class methods

[]?(name : String) : Primitive | Nil
Source
broken_probe?(exit_code : Int32, stderr : String) : Bool

Vrai si la commande ne s'est pas exécutée correctement (≠ « non ») : l'étape doit alors être FAILED, jamais un « would apply » muet.

Source
pkg_install(shell : Shell, packages : Array(String)) : Nil

pkg install -y des packages, avec -r <dépôt> : le dépôt que pkg choisit lui-même pour chacun (plan pkg install -n, lignes « \tnom: version [dépôt] »), un appel par dépôt. Sans -r, un paquet offert par deux dépôts (gmp, mpfr… republiés par poudriere dans le dépôt maison, copies de FreeBSD-ports) échappe à la règle « ne pas installer ce qui n'est pas installé » du solveur de pkg (posée seulement quand il n'en existe qu'UNE variante, libpkg/pkg_solve.c) : pkg install smartmontools installait aussi gmp et mpfr, que rien ne réclame (shingouz, 27 oct. 2026). Un paquet absent du plan : sans -r.

Source
planned_repos(plan : String) : Hash(String, String)

Dépôt de chaque paquet d'un plan pkg install -n / pkg upgrade -n (« \tnom: version [dépôt] » ou « \tnom: a -> b [dépôt] »). Pur.

Source
probe?(shell : Shell, command : String) : Bool

Sonde oui/non : vrai si command sort en 0, faux si elle répond « non », ProbeFailed si elle n'a pas pu s'exécuter (cf. read_probe).

Source
read_probe(shell : Shell, command : String) : SSH::Result

Sonde en LECTURE de l'état (test -e, pkg info -e, sysrc -n…) : le résultat tel quel, que la commande réponde oui ou non, mais ProbeFailed (→ étape FAILED) si le shell n'a pas pu la jouer. Sans ce filtre, une sonde cassée passait pour « pas encore fait » : « would apply » muet en dry-run.

Source
register(primitive : Primitive) : Nil
Source
registry
Source
repo_groups(names : Array(String), repo_of : Hash(String, String)) : Array(Tuple(String | Nil, Array(String)))

Groupes {dépôt, paquets} dans l'ordre de names ; nil = dépôt inconnu (pkg sans -r). Pur.

Source
service_command(svc : String, action : String, timeout : Int32 | Nil = nil) : String
Source

Instance methods

apply(shell : Shell, params : Hash(String, YAML::Any), dry_run : Bool, context : Context) : StepResult

params est le hash brut du step YAML (ex: {"packages" => [...]}), déjà interpolé par l'Executor. context porte les infos dérivées du host (cf. Context).

Source
name

Nom kebab-case utilisé comme clé de step dans les recettes (« pkg-install », « service-enable », …).

Source
systems

Systèmes sur lesquels la primitive sait agir. FreeBSD seul par défaut : une primitive portable (ou portée) le déclare en redéfinissant cette méthode. L'Executor refuse une primitive hors de sa liste.

Source

Nested types