Custom template functions in the overlay
Updated 5 Novembre 2026
- Où placer une fonction
- Choisir le langage du fichier
- Remplacement des fonctions intégrées
- Protocole d'appel
- Deux issues distinctes : fonction introuvable et fonction en erreur
- Des noms qui ne sont pas des fonctions
- Votre propre script passe avant une fonction intégrée
- Une astuce à reprendre
- Voir aussi
En plus des fonctions intégrées (mergepkg(), pkg(), exists(), ini(), grep(), cut(), …), les utilitaires vous permettent de définir les vôtres - un simple script dans l'overlay. C'est un moyen d'introduire dans le modèle un contrôle qu'une condition ne peut pas exprimer : si une interface réseau existe, si un fournisseur est accessible, quel profil est actif.
Où placer une fonction
Une fonction est un fichier du répertoire scripts/functions/ du dépôt de l'overlay :
<location>/scripts/functions/checkdev.sh
Ici <location> est le chemin du dépôt issu du paramètre location de la section /etc/portage/repos.conf ; les modèles de ce dépôt se trouvent dans le même <location>/profiles/templates, donc la fonction est disponible dans tous les modèles du dépôt. Le nom de la fonction est la partie du nom de fichier jusqu'au premier point, donc l'extension n'a pas d'effet sur le nom
# Calculate checkdev(wan0)!= path=/etc/conf.d
Choisir le langage du fichier
Le fichier de fonction peut être écrit dans n'importe quel langage dont l'interpréteur est présent sur le système
Le fichier de fonction peut être écrit dans n'importe quel langage dont l'interpréteur est présent sur le système : le système lit lui-même la première ligne, et le moteur n'a pas besoin d'exécuter le fichier - il en lit le texte et le passe à l'interpréteur en entrée, donc le fichier n'a pas besoin d'être exécutable. La ligne #! est facultative elle aussi : sans elle, le fichier est lancé via sh. Par exemple, le fichier . Par exemple, le fichier cflang.py peut ressembler à ceci
#!/usr/bin/env python3
import sys
print("PY-OK " + (sys.argv[1] if len(sys.argv) > 1 else "?"))
Il est plus fiable de définir l'interpréteur via env - #!/usr/bin/env python3, et non par un chemin absolu : si le fichier indiqué par un chemin absolu n'existe pas, la fusion ne se contente pas de râler, elle s'arrête et ne va pas à son terme ; avec la forme env un interpréteur absent se voit dans le même avertissement que les autres pannes.
On appelle un tel fichier avec la construction #-cflang(hello)-#, et elle substitue PY-OK hello dans le modèle. Les arguments parviennent au script sous forme de paramètres séparés après --, donc sys.argv voit à la fois le nom de la fonction et ses valeurs. Conséquence utile : le texte de la fonction passe d'abord par le traitement ordinaire des modèles, donc les variables et les appels de la forme #-…-# écrits dans le fichier de fonction sont substitués avant même le lancement du script.
Remplacement des fonctions intégrées
Une fonction de scripts/functions/ est vérifiée avant la fonction intégrée et la remplace est vérifiée avant la fonction intégrée et la remplace : si vous déposez un fichier portant le nom de
Une fonction de scripts/functions/ est vérifiée avant la fonction intégrée et la remplace est vérifiée avant la fonction intégrée et la remplace : si vous déposez un fichier portant le nom de
une fonction standard, l'étiquette appellera votre script. Un script exists avec echo SHADOW-OK renvoie au modèle
SHADOW-OK à la place de la réponse normale de la fonction intégrée, et un script Python renvoie PY-OK hello. Traitez
les noms des fonctions intégrées avec précaution : le remplacement s'applique à
tous les modèles de ce dépôt, et il est facile de ne pas le remarquer.tous les modèles de ce dépôt, et il est facile de ne pas le remarquer.
tous les modèles de ce dépôt, et il est facile de ne pas le remarquer.tous les modèles de ce dépôt, et il est facile de ne pas le remarquer.
Protocole d'appel
Une fonction est un script ordinaire, et le protocole de retour est le suivant :
- stdout - la valeur du texte à substituer ;
- descripteur de fichier 3 - un avertissement (il se retrouve dans la sortie comme WARNING) ;
- descripteur de fichier 4 - un message de succès (SUCCESS) ;
- un code de retour non nul - une erreur.
Un exemple tiré d'un vrai overlay - vérifier qu'une interface existe :
scripts/functions/checkdev.sh
#!/bin/bash # Vérifier l'existence d'une interface réseau # paramètres : nom # Renvoie ce même nom si l'interface existe if ip link show $1 &>/dev/null; then echo $1 exit 0 fi
Une telle fonction dans un modèle donne le nom de l'interface si elle existe et rien si elle n'existe pas, et, avec la condition checkdev(wan0)!= полностью отключает целый шаблон на машинах без этого интерфейса.
Deux issues distinctes : fonction introuvable et fonction en erreur
Il est important de les distinguer lors du débogage.
- Nom de fonction introuvable (le nom ne figure ni parmi les fonctions intégrées, ni dans scripts/functions d'un quelconque dépôt) - le modèle s'interrompt avec le message
function of templates '<name>' not found. Une faute de frappe dans un nom de fonction coûte plus cher qu'il n'y paraît : tout le modèle cesse de fonctionner. - Le script existe mais s'est terminé sur une erreur (un code de retour non nul, un interpréteur absent, un texte que l'interpréteur ne peut pas exécuter) - les utilitaires affichent l'avertissement
Failed to apply custom function …et substituent une valeur vide ; le modèle se poursuit. Si la fonction était dans une condition, le résultat sera généralement "la condition est fausse", et vous obtiendrez un modèle non appliqué en silence, et non une erreur.
Conclusion pratique : rendez la fonction "sûre par défaut" - quelle que soit la panne, elle devrait afficher ce qui correspond au comportement voulu quand on ne sait rien (en général une ligne vide et exit 0), et vous pourrez distinguer "pas de données" de "ça a planté" grâce à l'avertissement.
Des noms qui ne sont pas des fonctions
Certaines constructions #-…-# sont des variables, pas des fonctions, et chercher leur présence dans scripts/functions n'a pas de sens. Par exemple, #-cl_pass_file-# est le nom du fichier de modèle en cours de traitement, que les utilitaires substituent eux-mêmes (pour un répertoire, le nom du répertoire) ; c'est pourquoi la construction #-cut(1)-# est utilele champ 1 est le second).
La distinction est simple : une fonction se différencie d'une variable par les deux parenthèses d'arguments (), même s'il n'y a pas d'arguments. cl_pass_file dans #-cl_pass_file-# est une variable ; #-cl_pass_file()-# est déjà l'appel d'une fonction portant ce nom. Une construction sans parenthèses n'est jamais comptée comme une fonction.
Votre propre script passe avant une fonction intégrée
Le répertoire scripts/functions/ est parcouru avant la liste des fonctions intégréesun script comme ini.sh ou cut.sh éclipse les ini() et cut() intégrés dans tous les modèles de ce dépôt - et, au lieu d'un "j'ai redéfini une fonction", vous obtenez un comportement qui a changé en silence là où on n'attendait pas ces noms. Le nom d'une fonction intégrée est donc un mauvais nom pour votre propre script ; en cas de comportement suspect, vérifiez si scripts/functions/ ne contient pas un fichier portant ce nom.
Si des scripts portant le même nom existent dans plusieurs dépôts, le dernier de la liste des dépôts est lancé : d'abord les dépôts Calculate du repos.conf principal (dans l'ordre de leurs sections), puis les autres dépôts non-Portage de repos.conf.d/*.conf.
Une astuce à reprendre
Les fonctions se marient bien avec cut() et ini() : le nom du modèle porte les données (link.<file>, runlevel-<service>, <index>-<name>), et la fonction les décompose. Ainsi, un seul modèle court donne une famille de liens et d'entrées de services, et la liste de "quoi configurer" est conservée dans ini.env - donc c'est l'administrateur qui la modifie, et non une retouche de l'overlay.
Voir aussi
- Syntaxe du modèle - fonctions intégrées et conditions.
- Le modèle ne s'applique pas et ne dit rien - la différence entre "introuvable" et "en erreur".
- Répertoires de modèles et niveaux de stockage - où vivent les dépôts.