hu?
This commit is contained in:
parent
940b20f5d9
commit
e260ec427d
3905 changed files with 50410 additions and 24236 deletions
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# Rougail
|
||||
|
||||
Rougail est un bibliothèque python3 qui permet de charger des dictionnaires (fichiers au format XML ou YAML), de charger les variables dans Tiramisu et de générer des templates Cheetah ou Jinja.
|
||||
Rougail est un bibliothèque python3 qui permet de charger des dictionnaires (fichiers au format YAML), de charger les variables dans Tiramisu.
|
||||
|
||||

|
||||
|
||||
|
|
@ -19,23 +19,11 @@ Rougail est un bibliothèque python3 qui permet de charger des dictionnaires (fi
|
|||
|
||||
### Les variables
|
||||
|
||||
- [Les familles](family/README.md)
|
||||
- [Les variables](variable/README.md)
|
||||
|
||||
### Les services
|
||||
|
||||
- [La gestion d'un fichier](service/file.md)
|
||||
- [La gestion d'un certificat](service/certificate.md)
|
||||
- [La gestion d'un fichier de service systemd](service/override.md)
|
||||
- [La gestion d'une ip](service/ip.md)
|
||||
- [Les familles](family/README.md)
|
||||
|
||||
### Les contraintes
|
||||
|
||||
- [Les calculs automatiques](fill/README.md)
|
||||
- [Les vérifications des valeurs](check/README.md)
|
||||
- [Les conditions](condition/README.md)
|
||||
|
||||
## Les templates
|
||||
|
||||
- [Les moteurs de templates](template/README.md)
|
||||
- [Les patches](template/patch.md)
|
||||
|
|
|
|||
|
|
@ -6,49 +6,22 @@ Une fonction de vérification est une fonction complémentaire au type qui perme
|
|||
|
||||
Voici un exemple simple de validation des valeurs :
|
||||
|
||||
```xml
|
||||
<variables>
|
||||
<variable name="my_variable"/>
|
||||
</variables>
|
||||
<constraints>
|
||||
<check name="islower">
|
||||
<target>my_variable</target>
|
||||
</check>
|
||||
</constraints>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
variables:
|
||||
- variable:
|
||||
name: my_variable
|
||||
constraints:
|
||||
- check:
|
||||
- name: islower
|
||||
target:
|
||||
- text: my_variable
|
||||
```
|
||||
|
||||
|
||||
La [cible (de type variable)](../target/variable.md) de la fonction de vérification est ici "my_variable".
|
||||
|
||||
Dans cette exemple, la valeur de la variable "my_variable" va être validé par la fonction islower.
|
||||
|
||||
Voici le contenu de la fonction :
|
||||
|
||||
```python
|
||||
def islower(value):
|
||||
if value is None:
|
||||
return
|
||||
if not value.islower():
|
||||
raise ValueError(f'"{value}" is not lowercase string')
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
validators:
|
||||
- type: jinja
|
||||
jinja: |+
|
||||
{% if rougail.my_variable and not rougail.my_variable.islower() %}
|
||||
{{ rougail.my_variable }} is not lowercase string
|
||||
{% endif %}
|
||||
```
|
||||
|
||||
Une fonction de vérification doit prendre en compte 2 aspects important :
|
||||
|
||||
- la valeur peut ne pas être renseigné (même si la variable est obligatoire), la valeur None doit être prise en compte
|
||||
- si la valeur est invalide, il faut faire un raise de type ValueError avec, si possible, un message explicite.
|
||||
- si la valeur est invalide, il faut renvoyer une phrase avec un message explicite.
|
||||
|
||||
À partir de maintenant seule None et des valeurs en minuscule seront autorisés.
|
||||
|
||||
|
|
@ -58,20 +31,18 @@ Il est possible de définir des [paramètres](../param/README.md) à cette fonct
|
|||
|
||||
Dans la contrainte, il est possible de spécifier le niveau d'erreur et le mettre en avertissement :
|
||||
|
||||
```xml
|
||||
<check name="islower" level="warning">
|
||||
<target>my_variable</target>
|
||||
</check>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- check:
|
||||
- name: islower
|
||||
level: warning
|
||||
target:
|
||||
- text: my_variable
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
validators:
|
||||
- type: jinja
|
||||
jinja: |+
|
||||
{% if rougail.my_variable and not rougail.my_variable.islower() %}
|
||||
{{ rougail.my_variable }} is not lowercase string
|
||||
{% endif %}
|
||||
params:
|
||||
warning: true
|
||||
```
|
||||
|
||||
Dans ce cas une valeur avec une majuscule sera accepté, mais un message d'avertissement apparaitra.
|
||||
|
|
|
|||
|
|
@ -4,55 +4,31 @@
|
|||
|
||||
Dans un premier dictionnaire déclarons notre variable et sa fonction de vérification :
|
||||
|
||||
```xml
|
||||
<variables>
|
||||
<variable name="my_variable"/>
|
||||
</variables>
|
||||
<constraints>
|
||||
<check name="islower">
|
||||
<target>my_variable</target>
|
||||
</check>
|
||||
</constraints>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
variables:
|
||||
- variable:
|
||||
name: my_variable
|
||||
constraints:
|
||||
- check:
|
||||
- name: islower
|
||||
target:
|
||||
- text: my_variable
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
validators:
|
||||
- type: jinja
|
||||
jinja: |+
|
||||
{% if rougail.my_variable and not rougail.my_variable.islower() %}
|
||||
{{ rougail.my_variable }} is not lowercase string
|
||||
{% endif %}
|
||||
```
|
||||
|
||||
Dans un second dictionnaire il est possible de redéfinir le calcul :
|
||||
|
||||
```xml
|
||||
<variables>
|
||||
<variable name="my_variable" redefine="True"/>
|
||||
</variables>
|
||||
<constraints>
|
||||
<check name="isspace">
|
||||
<target>my_variable</target>
|
||||
</check>
|
||||
</constraints>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
variables:
|
||||
- variable:
|
||||
name: my_variable
|
||||
redefine: true
|
||||
constraints:
|
||||
- check:
|
||||
- name: isspace
|
||||
target:
|
||||
- text: my_variable
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
redefine: true
|
||||
validators:
|
||||
- type: jinja
|
||||
jinja: |+
|
||||
{% if rougail.my_variable and ' ' in rougail.my_variable %}
|
||||
{{ rougail.my_variable }} has a space
|
||||
{% endif %}
|
||||
```
|
||||
|
||||
Dans ce cas, la fonction "islower" exécuté. Si cette fonction ne retourne pas d'erreur, la seconde fonction "isspace" sera exécuté.
|
||||
|
|
@ -65,44 +41,24 @@ Dans un second dictionnaire il est possible de supprimer cette vérification.
|
|||
|
||||
Dans un premier dictionnaire déclarons notre variable et notre fonction de vérification :
|
||||
|
||||
```xml
|
||||
<variables>
|
||||
<variable name="my_variable"/>
|
||||
</variables>
|
||||
<constraints>
|
||||
<check name="islower">
|
||||
<target>my_variable</target>
|
||||
</check>
|
||||
</constraints>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
variables:
|
||||
- variable:
|
||||
name: my_variable
|
||||
constraints:
|
||||
- check:
|
||||
- name: islower
|
||||
target:
|
||||
- text: my_variable
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
validators:
|
||||
- type: jinja
|
||||
jinja: |+
|
||||
{% if rougail.my_variable and not rougail.my_variable.islower() %}
|
||||
{{ rougail.my_variable }} is not lowercase string
|
||||
{% endif %}
|
||||
```
|
||||
|
||||
Dans un second dictionnaire supprimer cette vérification :
|
||||
|
||||
```xml
|
||||
<variables>
|
||||
<variable name="my_variable" redefine="True" remove_check="True"/>
|
||||
</variables>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
variables:
|
||||
- variable:
|
||||
name: my_variable
|
||||
redefine: true
|
||||
remove_check: true
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
redefine: true
|
||||
validators:
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,47 +1,53 @@
|
|||
# Les conditions
|
||||
# Les propriétés calculées
|
||||
|
||||
## Un condition
|
||||
Les propriétés calculées permettent d'ajouter ou de supprimer des propriétés à une [variable](../variable/README.md) ou une [famille](../family/README.md) suivant le contexte.
|
||||
|
||||
Les conditions permettent d'ajouter ou de supprimer des propriétés à une [variable](../variable/README.md), une [famille](../family/README.md), un [service](../service/README.md), un [fichier](../service/file.md) ou une [ip](../service/ip.md) suivant le contexte.
|
||||
Nous allons nous concentrer ici sur la proprété `hidden`, mais ce qui est dit est vrai pour toutes les propriétés.
|
||||
|
||||
Nous allons nous concentrer ici sur la condition hidden_if_in, mais [il existe d'autre conditions](conditions.md).
|
||||
## Une propriété calculée de type variable
|
||||
|
||||
La condition hidden_if_in permet de cacher une variable où une famille à l'utilisateur, mais cette variable est toujours accessible dans un calcul, un vérification ou dans un template.
|
||||
Une variable peut donc être calculé via la résultat d'une autre variable.
|
||||
Attention, cette autre variable doit obligatoirement être de type `boolean` :
|
||||
|
||||
```xml
|
||||
<variables>
|
||||
<variable name="condition" type="boolean"/>
|
||||
<variable name="my_variable"/>
|
||||
</variables>
|
||||
|
||||
<constraints>
|
||||
<condition name="hidden_if_in" source="condition">
|
||||
<param>True</param>
|
||||
<target>my_variable</target>
|
||||
</condition>
|
||||
</constraints>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
variables:
|
||||
- variable:
|
||||
name: condition
|
||||
type: boolean
|
||||
- variable:
|
||||
name: my_variable
|
||||
constraints:
|
||||
- condition:
|
||||
- name: hidden_if_in
|
||||
source: condition
|
||||
param:
|
||||
- text: true
|
||||
target:
|
||||
- text: my_variable
|
||||
---
|
||||
version: '1.0'
|
||||
condition:
|
||||
type: boolean
|
||||
my_variable:
|
||||
hidden:
|
||||
type: variable
|
||||
variable: rougail.condition
|
||||
```
|
||||
|
||||
Le [paramètres](../param/README.md) de la condition permet de définir les valeurs que doit avoir la source pour appliquer l'action.
|
||||
Si la valeur de la variable "rougail.condition" est `True` alors la variable "rougail.my_variable" est cachée.
|
||||
|
||||
## Une propriété calculée de type jinja
|
||||
|
||||
Il est possible d'écrire la condition en Jinja :
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
condition:
|
||||
default: 'do not hide!'
|
||||
my_variable:
|
||||
hidden:
|
||||
type: jinja
|
||||
jinja: |
|
||||
{% if rougail.condition and rougail.condition == "hide!" %}
|
||||
true
|
||||
{% else %}
|
||||
false
|
||||
{% endif %}
|
||||
```
|
||||
|
||||
Dans ce cas la variable est cachée si la valeur de la variable "rougail.condition" est `hide!` et elle n'a pas caché pour tout autre valeur.
|
||||
Attention toujours prendre en considération que "rougail.condition" peut être égale à `None`.
|
||||
|
||||
Il est possible d'ajouter des [paramètres](../param/README.md) à la condition de type `jinja`.
|
||||
Il est possible d'ajouter des paramètres à la fonction
|
||||
|
||||
La [cible](../target/README.md) de la condition est ici "my_variable".
|
||||
|
||||
|
|
|
|||
|
|
@ -1,58 +1,42 @@
|
|||
# La bibliothèque Rougail
|
||||
|
||||
Rougail est une bibliothèque qui permet de charger simplement des dictionnaires et de générer des templates.
|
||||
Rougail est une bibliothèque de gestion de configuration qui permet de charger simplement des variables.
|
||||
|
||||
Dans les exemples suivant, nous utiliserons une configuration particulière de Rougail.
|
||||
Vous retrouverez toutes les options pour [personnaliser les répertoires utilisés](config.md).
|
||||
|
||||
Le script contiendra donc les éléments de configuration suivant :
|
||||
Pour changer la configuration il faut importer la variable RougailConfig et changer les valeurs :
|
||||
|
||||
```python
|
||||
from rougail import RougailConfig
|
||||
|
||||
RougailConfig['dictionaries_dir'] = ['dict']
|
||||
RougailConfig['templates_dir'] = ['tmpl']
|
||||
RougailConfig['tmp_dir'] = 'tmp'
|
||||
RougailConfig['destinations_dir'] = 'dest'
|
||||
RougailConfig['functions_file'] = 'funcs/functions.py'
|
||||
```
|
||||
|
||||
Penser a créer les répertoires :
|
||||
|
||||
```bash
|
||||
$ mkdir dest dict tmp tmpl extras
|
||||
```
|
||||
|
||||
## Convertisons un dictionnaire
|
||||
|
||||
Un dictionnaire est un ensemble d'instruction qui vont permettre de créer des variables.
|
||||
Un dictionnaire est un ensemble d'instruction qui vont permettre de créer des familles et des variables.
|
||||
|
||||
Commençons par créer un [dictionnaire](../dictionary/rougail.md) simple.
|
||||
|
||||
Voici un premier dictionnaire dict/00-base.yml :
|
||||
|
||||
```yml
|
||||
version: '0.10'
|
||||
variables:
|
||||
- variable:
|
||||
- name: my_variable
|
||||
value:
|
||||
- text: my_value
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
default: my_value
|
||||
```
|
||||
|
||||
Puis, créons les objets [Tiramisu](https://framagit.org/tiramisu/tiramisu) :
|
||||
Puis, créons les objets [Tiramisu](https://forge.cloud.silique.fr/gnunux/tiramisu) via la script script.py suivant :
|
||||
|
||||
```python
|
||||
from rougail import Rougail, RougailConfig
|
||||
from asyncio import run
|
||||
|
||||
async def main():
|
||||
RougailConfig['dictionaries_dir'] = ['dict']
|
||||
rougail = Rougail()
|
||||
config = await rougail.get_config()
|
||||
print(await config.value.dict())
|
||||
|
||||
run(main())
|
||||
RougailConfig['dictionaries_dir'] = ['dict']
|
||||
rougail = Rougail()
|
||||
config = rougail.get_config()
|
||||
print(config.value.dict())
|
||||
```
|
||||
|
||||
Exécution le script :
|
||||
|
|
@ -78,28 +62,22 @@ RougailConfig['extra_dictionaries']['example'] = ['extras/']
|
|||
Ensuite créons un dictionnaire extra extras/00-base.yml :
|
||||
|
||||
```yml
|
||||
version: '0.10'
|
||||
variables:
|
||||
- variable:
|
||||
- name: my_variable_extra
|
||||
value:
|
||||
- text: my_value_extra
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable_extra:
|
||||
default: my_value_extra
|
||||
```
|
||||
|
||||
Construisons les objets Tiramisu :
|
||||
Puis, créons les objets [Tiramisu](https://forge.cloud.silique.fr/gnunux/tiramisu) via la script script.py suivant :
|
||||
|
||||
```python
|
||||
from rougail import Rougail, RougailConfig
|
||||
from asyncio import run
|
||||
|
||||
async def main():
|
||||
RougailConfig['dictionaries_dir'] = ['dict']
|
||||
RougailConfig['extra_dictionaries']['example'] = ['extras/']
|
||||
rougail = Rougail()
|
||||
config = await rougail.get_config()
|
||||
print(await config.value.dict())
|
||||
|
||||
run(main())
|
||||
RougailConfig['dictionaries_dir'] = ['dict']
|
||||
RougailConfig['extra_dictionaries']['example'] = ['extras/']
|
||||
rougail = Rougail()
|
||||
config = rougail.get_config()
|
||||
print(config.value.dict())
|
||||
```
|
||||
|
||||
Exécution le script :
|
||||
|
|
@ -109,67 +87,18 @@ $ python3 script.py
|
|||
{'rougail.my_variable': 'my_value', 'example.my_variable_extra': 'my_value_extra'}
|
||||
```
|
||||
|
||||
## Templatisons un fichier
|
||||
|
||||
Un [template](../template/README.md) est un fichier dans lequel on va remplacer les valeurs attendues par le nom des variables.
|
||||
|
||||
Premièrement déclarons dans un dictionnaire complémentaire notre template dict/00-template.yml :
|
||||
|
||||
```yml
|
||||
version: '0.10'
|
||||
services:
|
||||
- service:
|
||||
- name: test
|
||||
file:
|
||||
- text: /etc/example.conf
|
||||
```
|
||||
|
||||
Et un template tmpl/example.conf (par défaut il est généré via une configuration particulière de [Cheetah](https://cheetahtemplate.org/) :
|
||||
|
||||
```
|
||||
The value: %%my_variable
|
||||
|
||||
The extra value: %%example.my_variable_extra
|
||||
```
|
||||
|
||||
Générons le template :
|
||||
|
||||
```python
|
||||
from rougail import Rougail, RougailConfig
|
||||
from asyncio import run
|
||||
|
||||
async def main():
|
||||
RougailConfig['dictionaries_dir'] = ['dict']
|
||||
RougailConfig['templates_dir'] = ['tmpl']
|
||||
RougailConfig['tmp_dir'] = 'tmp'
|
||||
RougailConfig['destinations_dir'] = 'dest'
|
||||
RougailConfig['extra_dictionaries']['example'] = ['extras/']
|
||||
RougailConfig['functions_file'] = 'funcs/functions.py'
|
||||
rougail = Rougail()
|
||||
await rougail.template()
|
||||
|
||||
run(main())
|
||||
```
|
||||
|
||||
Le fichier dest/etc/example.conf est maintenant créé avec le contenu attendu suivant :
|
||||
|
||||
```
|
||||
The value: my_value
|
||||
|
||||
The extra value: my_value_extra
|
||||
```
|
||||
|
||||
## Créons une fonction personnalisé
|
||||
|
||||
Nous créons le dictionnaire complémentaire dict/00-fill.yml pour que la variable "my_variable" soit [calculée](fill/README.md) :
|
||||
Nous créons le dictionnaire complémentaire dict/01-function.yml pour que la variable "my_variable_jinja" soit [calculée](fill/README.md) :
|
||||
|
||||
```yml
|
||||
version: '0.10'
|
||||
constraints:
|
||||
- fill:
|
||||
- name: return_no
|
||||
target:
|
||||
- text: my_variable
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable_jinja:
|
||||
type: "string"
|
||||
default:
|
||||
type: jinja
|
||||
jinja: "{{ return_no() }}"
|
||||
```
|
||||
|
||||
Puis créons la fonction "return_no" dans functions.py :
|
||||
|
|
@ -179,41 +108,24 @@ def return_no():
|
|||
return 'no'
|
||||
```
|
||||
|
||||
Après avoir reconverti les dictionnaires et regénérer le template nous avons donc le contenu du fichier dest/etc/example.conf :
|
||||
|
||||
```
|
||||
The value: no
|
||||
|
||||
The extra value: my_value_extra
|
||||
```
|
||||
|
||||
La valeur de la variable "my_variable" est bien calculé à partir de la fonction "return_no".
|
||||
|
||||
## Template et systemd
|
||||
|
||||
Rougail peut également généré automatiquement le fichier [tmpfiles.d](https://www.freedesktop.org/software/systemd/man/tmpfiles.d.html) pour installer automatiquement les fichiers de configuration au démarrage de la machine.
|
||||
|
||||
Pour générer le fichier tmpfiles.d, ajouter l'argument "systemd" à la methode "template" :
|
||||
Puis, créons les objets [Tiramisu](https://forge.cloud.silique.fr/gnunux/tiramisu) via la script script.py suivant :
|
||||
|
||||
```python
|
||||
from rougail import Rougail, RougailConfig
|
||||
from asyncio import run
|
||||
|
||||
async def main():
|
||||
RougailConfig['dictionaries_dir'] = ['dict']
|
||||
RougailConfig['templates_dir'] = ['tmpl']
|
||||
RougailConfig['tmp_dir'] = 'tmp'
|
||||
RougailConfig['destinations_dir'] = 'dest'
|
||||
RougailConfig['extra_dictionaries']['example'] = ['extras/']
|
||||
RougailConfig['functions_file'] = 'funcs/functions.py'
|
||||
rougail = Rougail()
|
||||
await rougail.template('systemd')
|
||||
|
||||
run(main())
|
||||
RougailConfig['dictionaries_dir'] = ['dict']
|
||||
RougailConfig['extra_dictionaries']['example'] = ['extras/']
|
||||
RougailConfig['functions_file'] = 'functions.py'
|
||||
rougail = Rougail()
|
||||
config = rougail.get_config()
|
||||
print(config.value.dict())
|
||||
```
|
||||
|
||||
Ainsi le fichier supplémentaire "dest/tmpfiles.d/0rougail.conf" sera créé avec le contenu :
|
||||
Exécution le script :
|
||||
|
||||
```python
|
||||
$ python3 script.py
|
||||
{'rougail.my_variable': 'my_value', 'rougail.my_variable_jinja': 'no', 'example.my_variable_extra': 'my_value_extra'}
|
||||
```
|
||||
C /etc/example.conf 0644 root root - /usr/local/lib/etc/example.conf
|
||||
```
|
||||
|
||||
La valeur de la variable `my_variable_extra` est bien calculé à partir de la fonction `return_no`.
|
||||
|
|
|
|||
|
|
@ -14,29 +14,17 @@ Pour modifier il suffit de faire :
|
|||
RougailConfig[key] = value
|
||||
```
|
||||
|
||||
## Ajout d'une fonction de conversion
|
||||
|
||||
Les fonctions de conversion fait parti du moteur de rougail. Il converti les informations des dictionnaires pour créer des variables Tiramisu.
|
||||
|
||||
La clef "extra_annotators" permet d'ajouter des fonctions complémentaires.
|
||||
|
||||
## Configuration de chargement des dictionnaires
|
||||
|
||||
### Les répertoires des dictionnaires
|
||||
|
||||
Il existe deux types de répertoires de dictionnaires :
|
||||
|
||||
- les dictionnaires principaux avec la clef "dictionaries_dir". La valeur par défaut est ['/srv/rougail/dictionaries']. Cette variable doit contenir la liste des répertoires contenants des dictionnaires.
|
||||
- les dictionnaires principaux avec la clef `dictionaries_dir`. La valeur par défaut est `['/srv/rougail/dictionaries']`. Cette variable doit contenir la liste des répertoires contenants des dictionnaires.
|
||||
|
||||
Les dictionnaires sont chargés dans l'ordre des répertoires. Chaque répertoire est chargé les uns après les autres. A l'intérieur de ces répertoires les fichiers XML ou YAML seront classés par ordre alphabétique.
|
||||
- les dictionnaires extra avec la clef `extra_dictionaries`. La valeur est un dictionnaire avec l'ensemble des espaces de nom. La clef étant l'espace de nom et la valeur étant une liste de répertoire.
|
||||
|
||||
Il n'y a pas de classement par ordre alphabétique de l'ensemble des fichiers XML ou YAML de tous les répertoires.
|
||||
|
||||
Les familles et variables de ces dictionnaires sont classés, par défaut, dans l'espace de nom "rougail". Il est possible de changer le nom de cet espace de nom avec la clef "variable_namespace".
|
||||
|
||||
- les dictionnaires extra avec la clef "extra_dictionaries". La valeur est un dictionnaire avec l'ensemble des espaces de nom. La clef étant l'espace de nom et la valeur étant une liste de répertoire.
|
||||
|
||||
Par exemple pour ajouter l'extra "example" il faut faire :
|
||||
Par exemple pour ajouter l'extra `example` il faut faire :
|
||||
|
||||
```python
|
||||
RougailConfig['extra_dictionaries']['example'] = ['/dir1', '/dir2']
|
||||
|
|
@ -44,14 +32,6 @@ RougailConfig['extra_dictionaries']['example'] = ['/dir1', '/dir2']
|
|||
|
||||
Les dictionnaires sont chargés dans le même ordre que les dictionnaires principaux.
|
||||
|
||||
### La DTD et le schema YAML
|
||||
|
||||
Rougail a besoin du fichier de la DTD pour lire les fichiers dictionnaire de type XML et du schema YAML pour les fichiers dictionnaire de type YAML.
|
||||
|
||||
Par défaut le fichier de la DTD et le schema YAML sont dans le sous répertoire "data" du répertoire de code. Le nom du fichier est rougail.dtd et rougail.yml.
|
||||
|
||||
Pour pouvez changer le nom du fichier DTD avec la clef "dtdfilename" et le nom du schema YAML avec la clef "yamlschema_filename".
|
||||
|
||||
### Le fichier de fonction
|
||||
|
||||
Le fichier qui contient les fonctions personnalisés est géré dans la clef "functions_file" et a comme valeur par défaut "/srv/rougail/functions.py". Cette clef peut contenir une liste s'il y a plusieurs fichiers.
|
||||
|
|
@ -147,3 +127,10 @@ La méthode d'inclusion des fichiers générés est géré dans la clef "default
|
|||
## La configuration du moteur de templates
|
||||
|
||||
Le moteur de template est géré dans la clef "default_overrides_engine" et a comme valeur par défaut : "cheetah". Les valeurs possible sont "none", "cheetah" ou "jinja".
|
||||
|
||||
## Ajout d'une fonction de conversion
|
||||
|
||||
Les fonctions de conversion fait parti du moteur de rougail. Il converti les informations des dictionnaires pour créer des variables Tiramisu.
|
||||
|
||||
La clef "extra_annotators" permet d'ajouter des fonctions complémentaires.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +1,7 @@
|
|||
# Convention de rédaction d'un dictionnaire
|
||||
|
||||
## Ordonnancement du dictionnaire
|
||||
|
||||
L'ordre des informations mise dans le dictionnaire est idéalement :
|
||||
|
||||
- services
|
||||
- variables
|
||||
- constraintes
|
||||
|
||||
## Nom des fichiers de dictionnaire
|
||||
# Convention de nom d'un fichier de dictionnaire
|
||||
|
||||
L'ordre des dictionnaires est important pour l'ordre de création des variables et des familles.
|
||||
|
||||
Les fichiers devront donc démarrés par deux numéros suivit d'un tiret.
|
||||
|
||||
Par exemple : 00-base.xml
|
||||
|
||||
## Le nombre d'espace XML
|
||||
|
||||
Le nombre d'espace dans un dictionnaire au format XML est de deux espaces.
|
||||
Par exemple : `00-base.xml`
|
||||
|
|
|
|||
|
|
@ -4,9 +4,4 @@ Un extra est un espace de nom différent. L'idée et de pouvoir classer les vari
|
|||
|
||||
Les espaces de nom extra doivent être déclaré au moment [de la configuration de Rougail](../dev/config.md).
|
||||
|
||||
Dans cet espace de nom :
|
||||
|
||||
- des variables et des familles peuvent avoir le même nom dans différentes familles
|
||||
- la valeur d'un cible, source, leader ou follower des contraintes doivent être avec un chemin complet
|
||||
- on ne peut pas déclarer des services dans cet espace de nom
|
||||
- dans un template il faut utiliser des chemins complet (%%my_extra.my_family.my_variable ou %%my_extra.my_family.leader.follower pour une variable suiveuse)
|
||||
Dans cet espace de nom on ne peut pas accéder a des variables d'un autre espace de nom `extra`. Par contre il est possible d'accéder au variable de l'espace de nom par défaut.
|
||||
|
|
|
|||
|
|
@ -2,21 +2,20 @@
|
|||
|
||||
## Un dictionnaire ?
|
||||
|
||||
Un dictionnaire est un fichier XML ou YAML donc la structure est décrite dans cette documentation.
|
||||
Un dictionnaire est un fichier YAML dont la structure est décrite dans cette documentation.
|
||||
|
||||
Un dictionnaire contient en ensemble de variable chargé dans Tiramisu, utilisable à tout moment, notamment dans des templates.
|
||||
Un dictionnaire contient en ensemble de variable chargé dans [Tiramisu](https://forge.cloud.silique.fr/gnunux/tiramisu), utilisable à tout moment, notamment dans des templates.
|
||||
|
||||
Les familles, les variables et les contraintes peuvent être défini dans plusieurs dictionnaires. Ces dictionnaires s'aggrège alors.
|
||||
Les familles et les variables peuvent être défini dans plusieurs dictionnaires. Ces dictionnaires s'aggrègent alors.
|
||||
|
||||
Il est également possible de redéfinir des éléments pour changer les comportement d'une variable ou d'un service.
|
||||
Les dictionnaires sont chargés dans l'ordre des répertoires [définit avec le paramètre `dictionaries_dir` de la configuration](../dev/config.md). Chaque répertoire est chargé les uns après les autres. A l'intérieur de ces répertoires les fichiers YAML seront classés par ordre alphabétique.
|
||||
|
||||
Il n'y a pas de classement par ordre alphabétique de l'ensemble des fichiers YAML de tous les répertoires.
|
||||
|
||||
Il est également possible de redéfinir des éléments pour changer les comportement d'une famille ou d'une variable.
|
||||
|
||||
## L'espace de nom par défaut
|
||||
|
||||
L'espace de nom par défaut s'appelle "rougail" ([ce nom est personnalisable](../dev/config.md)).
|
||||
Les familles et variables de ces dictionnaires sont classées, par défaut, dans l'espace de nom `rougail`. Il est possible de changer le nom de cet espace de nom [avec le paramètre `variable_namespace` de la configuration](../dev/config.md).
|
||||
|
||||
Cet espace de nom est un peu particulier :
|
||||
|
||||
- le nom des variables et des familles doivent être unique pour l'ensemble de cet espace (même si ces variables ou familles sont dans des familles différentes)
|
||||
- la valeur d'un cible, source, leader ou follower des contraintes peuvent être avec nom de la variable ou de la famille ou leurs chemins complet
|
||||
- on peut déclarer des services dans cet espace de nom
|
||||
- dans un template on peut utiliser cette variable sans le chemin complet (%%my_variable) ou avec (%%rougail.my_family.my_variable)
|
||||
Cet espace de nom est un peu particulier, il peut accéder a des variables dans un autre espace de nom.
|
||||
|
|
|
|||
|
|
@ -1,46 +1,37 @@
|
|||
# Famille crée dynamiquement
|
||||
|
||||
Pour créer une famille dynamiquement, il faut créer une famille fictive lié à une variable.
|
||||
Le nom et la description de la famille et des variables qu'elle contient sera en réalité le prefix du nouveau nom/description. Le suffix viendra de la variable liée.
|
||||
Le nom et la description de la famille et des variables qu'elle contient sera en réalité le prefix du nouveau nom/description. Le suffix viendra de la valeur de la variable liée.
|
||||
|
||||
Par exemple :
|
||||
|
||||
```xml
|
||||
<variable name='varname' multi="True">
|
||||
<value>val1</value>
|
||||
<value>val2</value>
|
||||
</variable>
|
||||
<family name="my_dyn_family_" dynamic="varname" description="Describe ">
|
||||
<variable name="my_dyn_var_"/>
|
||||
</family>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
variables:
|
||||
- variable:
|
||||
name: variable
|
||||
multi: true
|
||||
value:
|
||||
- text: 'val1'
|
||||
- text: 'val2'
|
||||
- family:
|
||||
name: my_dyn_family_
|
||||
dynamic: varname
|
||||
description: 'Describe '
|
||||
variables:
|
||||
- variable:
|
||||
name: my_dyn_var_
|
||||
---
|
||||
version: '1.0'
|
||||
varname:
|
||||
multi: true
|
||||
default:
|
||||
- val1
|
||||
- val2
|
||||
my_dyn_family_:
|
||||
type: dynamic
|
||||
variable: rougail.varname
|
||||
description: 'Describe '
|
||||
my_dyn_var_:
|
||||
type: string
|
||||
```
|
||||
|
||||
Créera deux familles :
|
||||
|
||||
- la famille dynamique : "my_dyn_family_val1" avec la description "Describe val1"
|
||||
- la famille dynamique : "my_dyn_family_val2" avec la description "Describe val2"
|
||||
- la famille dynamique : "rougail.my_dyn_family_val1" avec la description "Describe val1"
|
||||
- la famille dynamique : "rougail.my_dyn_family_val2" avec la description "Describe val2"
|
||||
|
||||
Dans la famille dynamique "my_dyn_family_val1" on retrouvera une variable "my_dyn_var_val1".
|
||||
Dans la famille dynamique "rougail.my_dyn_family_val1" on retrouvera une variable "my_dyn_var_val1".
|
||||
|
||||
Bien évidement si le contenu de "varname" venait a évolué, de nouvelles familles dynamiques pouvent apparaitre ou des familles dynamiques peuvent disparaître.
|
||||
Bien évidement si le contenu de "varname" venait a évoluer, de nouvelles familles dynamiques apparaitront ou disparaîtront.
|
||||
|
||||
Attention la variable lié à la famille doit être obligatoirement une variable multiple et il n'est pas possible de mettre une famille dans une famille dynamique.
|
||||
A noter que :
|
||||
|
||||
- la variable liée à la famille doit être obligatoirement une variable multiple ;
|
||||
- il n'est pas possible de mettre une simple famille dans une famille dynamique ;
|
||||
- il est possible de mettre [une famille meneuse](leadership.md) dans une famille dynamique.
|
||||
|
|
|
|||
|
|
@ -1,14 +1,22 @@
|
|||
# Variable meneuse ou suiveuse
|
||||
|
||||
## Un famille meneuse
|
||||
|
||||
Les variables meneuses et suiveuses sont placées dans un famille meneuse.
|
||||
|
||||
Une famille meneuse ne peut pas contenir d'autre famille.
|
||||
|
||||
Le [mode](../variable/mode.md) par défaut de la famille meneuse est le mode de la variable meneuse.
|
||||
|
||||
## Variable meneuse
|
||||
|
||||
Une variable meneuse est une variable qui va guider la longueur d'autre variables (appelé variables suiveuse).
|
||||
Une variable meneuse est une variable qui va guider la longueur d'autres variables (appelé variables suiveuses).
|
||||
|
||||
Une variable meneuse est une [variable](../variable/README.md) qui est obligatoirement de type multiple.
|
||||
|
||||
Une variable meneuse peut être obligatoire.
|
||||
|
||||
Le [mode](../mode.md) par défaut correspond au plus petit mode définit par l'utilisateur des variables suiveuses.
|
||||
Le [mode](../variable/mode.md) par défaut correspond au plus petit mode définit pour les variables suiveuses.
|
||||
|
||||
## Variable suiveuse
|
||||
|
||||
|
|
@ -23,63 +31,35 @@ Cette variable peut être de type multiple. Dans ce cas, pour un index determin
|
|||
Une variable suiveuse peut être obligatoire. Cela signifie que lorsqu'une variable meneuse est renseigné, il faut obligatoirement que la variable suiveuse est également une valeur à l'index considéré.
|
||||
Si aucune valeur n'est définit pour la variable meneuse, aucune valeur n'est a spécifié pour la variable suiveuse.
|
||||
|
||||
Le [mode](../mode.md) par défaut d'une variable suiveuse correspond au [mode](../mode.md) de la variable meneuse.
|
||||
Le [mode](../variable/mode.md) par défaut d'une variable suiveuse correspond au [mode](../variable/mode.md) de la variable meneuse.
|
||||
|
||||
Si une variable meneuse est caché ou désactivé, les variables suiveuses le seront également.
|
||||
|
||||
## Définition des variables meneuse et suiveuse
|
||||
|
||||
Les variables meneuses et suiveuses doivent dans une famille de type "leadership".
|
||||
Une famille meneuse a un attribut type à "leadership". Le type est obligatoire.
|
||||
|
||||
Voici un exemple de définition d'une variable meneuse et de deux variables meneuses :
|
||||
|
||||
```xml
|
||||
<variables>
|
||||
<family name="family" leadership='True'>
|
||||
<variable name="leader" multi='True'/>
|
||||
<variable name="follower1"/>
|
||||
<variable name="follower2" multi='True'/>
|
||||
</family>
|
||||
</variables>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
variables:
|
||||
- family:
|
||||
name: family
|
||||
leadership: true
|
||||
variables:
|
||||
- variable:
|
||||
name: leader
|
||||
multi: true
|
||||
- variable:
|
||||
name: follower1
|
||||
- variable:
|
||||
name: follower2
|
||||
multi: true
|
||||
---
|
||||
version: '1.0'
|
||||
family:
|
||||
type: leadership
|
||||
leader:
|
||||
multi: true
|
||||
follower1:
|
||||
follower2:
|
||||
multi: true
|
||||
```
|
||||
|
||||
## Ajout d'une nouvelle variable suiveuse
|
||||
|
||||
Pour ajouter, dans un nouveau dictionnaire, une variable suiveuse à notre groupe, rien de plus simple, il suffit définir une ou des nouvelles variables dans la famille :
|
||||
|
||||
```xml
|
||||
<variables>
|
||||
<family name="family">
|
||||
<variable name="follower3"/>
|
||||
</family>
|
||||
</variables>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
Pour ajouter une nouvelle variable suiveuse, dans un nouveau dictionnaire, il suffit de définir une ou des nouvelles variables dans la famille meneuse :
|
||||
|
||||
```yml
|
||||
variables:
|
||||
- family:
|
||||
name: family
|
||||
variables:
|
||||
- variable:
|
||||
name: follower3
|
||||
---
|
||||
version: '1.0'
|
||||
family:
|
||||
follower3:
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,128 +1,29 @@
|
|||
# Une famille
|
||||
|
||||
Une famille est un conteneur de variables. Elle peut contenir également des familles.
|
||||
## Synopsis
|
||||
|
||||
Pour décrire une famille il faut mettre au minimum un nom :
|
||||
Une famille est un conteneur de variables et de sous-famille.
|
||||
|
||||
```xml
|
||||
<family name="my_family"/>
|
||||
```
|
||||
## Paramètres
|
||||
|
||||
En YAML :
|
||||
| Paramètre | Commentaire |
|
||||
|----------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| **name**<br/>`string`<br/>`mandatory` | Nom de la famille.<br/>C'est avec ce nom qu'on va pouvoir interagir avec la famille.<br/>Il est préférable de suivre la [convention sur les noms de variable](convention.md). |
|
||||
| **type** / **\_type**<br/>`string` | Type de la famille.<br/>Le type par défaut "family" n'est pas obligatoire même si parfois c'est nécessaire de le faire pour aiderle moteur.<br/>**Valeurs possible :**<br/>- `family` ← part defaut<br/>- `leadership`<br/>- `dynamic`<br/>📝 Si une sous-famille ou une sous-variable a déjà le nom "type" il est possible d'utiliser l'attribut "\_type". |
|
||||
| **description** / **\_description**<br/>`string` | La description de la famille.<br/>Information utilisateur permettant de comprendre l'utilité de la variable.<br/>📝 Si une sous-famille ou une sous-variable a déjà le nom "description" il est possible d'utiliser l'attribut "\_description". |
|
||||
| **help** / **\_help**<br/>`string` | Aide complémentaire associée à famille.<br/>📝 Si une sous-famille ou une sous-variable a déjà le nom "help" il est possible d'utiliser l'attribut "\_help". |
|
||||
| **mode** / **\_mode**<br/>`string` | [Mode](../variable/mode.md) de la famille/<br/>Le mode par défaut d'une famille est le mode le plus petit des familles parentes, les variables enfants ou des familles enfants qui sont conenus dans cette famille.<br/> Ce mode permet aussi de définir le mode par défaut des variables ou des familes inclusent dans cette famille.<br/>**Values:**<br/>- basic<br/>- normal ← default<br/>- expert<br/>📝 Si une sous-famille ou une sous-variable a déjà le nom "mode" il est possible l'attribut "\_mode". |
|
||||
| **hidden** / **\_hidden**<br/>`boolean` ou [`calculation`](../condition/README.md) | Famille invisible<br/>Permet de cacher une familles ainsi que les variables ou les familles inclusent dans cette famille.<br/>Cela signifie que la famille ne sera plus visible pour l'utilisateur mais pas pour un calcul.<br/>📝 Si une sous-famille ou une sous-variable a déjà le nom "hidden" il est possible l'attribut "\_hidden". |
|
||||
| **disabled** / **\_disabled**<br/>`boolean` ou [`calculation`](../condition/README.md) | Famille désactivée<br/> | Permet de désactiver une familles ainsi que les variables ou les familles inclusent dans cette famille.<br/>Cela signifie que la famille ne sera plus visible pour l'utilisateur mais "galement pour un calcul.<br/>📝 Si une sous-famille ou une sous-variable a déjà le nom "disabled" il est possible l'attribut "\_disabled". |
|
||||
|
||||
⚠️ Une famille sans sous-famille ou sous-variable sera automatiquement supprimée.
|
||||
|
||||
```yml
|
||||
- family:
|
||||
name: my_family
|
||||
```
|
||||
|
||||
Cette famille doit être placé dans une balise [variables](../variables.md) :
|
||||
|
||||
```xml
|
||||
<variables>
|
||||
<family name="my_family"/>
|
||||
</variables>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
variables:
|
||||
- family:
|
||||
name: my_family
|
||||
```
|
||||
|
||||
Ou dans une autre famille :
|
||||
|
||||
```xml
|
||||
<variables>
|
||||
<family name="my_family">
|
||||
<family name="second_family"/>
|
||||
</family>
|
||||
</variables>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
variables:
|
||||
- family:
|
||||
name: my_family
|
||||
variables:
|
||||
- family:
|
||||
name: second_family
|
||||
```
|
||||
|
||||
Attention, une famille vide sera automatiquement supprimée.
|
||||
|
||||
## Description et aide de la famille
|
||||
|
||||
En plus d'un nom, il est possible de mettre une "description" à la famille. C'est une information "utilisateur" qui nous permettra d'avoir des informations complémentaires sur le contenu de cette famille :
|
||||
|
||||
```xml
|
||||
<family name="my_family" description="This is a great family"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
variables:
|
||||
- family:
|
||||
name: my_family
|
||||
description: 'This is a great family'
|
||||
```
|
||||
|
||||
En plus de la description, il est possible de préciser une aide complémentaire :
|
||||
|
||||
```xml
|
||||
<family name="my_family" help="This is a great family"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
variables:
|
||||
- family:
|
||||
name: my_family
|
||||
help: 'This is a great family'
|
||||
```
|
||||
|
||||
## Mode de la famille
|
||||
|
||||
Le [mode](../mode.md) par défaut d'une famille correspond au [mode](../mode.md) du mode le plus petit entre la famille parente, les variables enfants ou des familles enfants qui sont contenu dans cette famille.
|
||||
|
||||
Changer le [mode](../mode.md) d'une famille permet de définir le [mode](../mode.md) par défaut des variables ou des familles inclusent dans cette famille.
|
||||
|
||||
Pour définir le [mode](../mode.md) :
|
||||
|
||||
```xml
|
||||
<family name="my_family" mode="expert"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- family:
|
||||
name: my_family
|
||||
mode: expert
|
||||
```
|
||||
|
||||
## Famille invisible
|
||||
|
||||
Il est possible de cacher une famille, ainsi que toutes les variables et des familles inclusent dans cette famille.
|
||||
|
||||
Cacher une famille signifie qu'elle ne sera pas visible lorsqu'on modifie la configuration du service.
|
||||
Par contre ces variables sont accessibles lorsqu'on va utiliser ces variables.
|
||||
|
||||
Pour cacher une famille :
|
||||
|
||||
```xml
|
||||
<family name="my_family" hidden="True"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- family:
|
||||
name: my_family
|
||||
hidden: true
|
||||
---
|
||||
version: '1.0'
|
||||
my_family:
|
||||
type: family
|
||||
description: This is a great family
|
||||
help: This the help of a great family
|
||||
mode: expert
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
# Les variables calculées
|
||||
|
||||
Une variable calculée est une variable donc sa valeur est le résultat d'une fonction python.
|
||||
Une variable calculée est une variable donc sa valeur est le résultat d'une fonction Python.
|
||||
|
||||
- [Valeur calculée de la variable](value.md)
|
||||
- [Réfinition](redefine.md)
|
||||
- [Exemples de calcule](examples.md)
|
||||
|
|
|
|||
|
|
@ -4,19 +4,6 @@
|
|||
|
||||
Créeons deux variables multiples, une pour accueillir la liste des éléments du nom variable (ici `zones_list`), la seconde étant le nom du fichier calculé (ici `netwokd_configurations`) :
|
||||
|
||||
```xml
|
||||
<variables>
|
||||
<variable name="zones_list" type="string" multi="True">
|
||||
<value>zone1</value>
|
||||
<value>zone2</value>
|
||||
<value>zone3</value>
|
||||
</variable>
|
||||
<variable name="netwokd_configurations" type="filename" multi="True" hidden="True"/>
|
||||
</variables>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
variables:
|
||||
- variable:
|
||||
|
|
@ -36,21 +23,6 @@ variables:
|
|||
|
||||
Calculons la valeur de la seconde variable à partir de la première :
|
||||
|
||||
```xml
|
||||
<constraints>
|
||||
<fill name="calc_value">
|
||||
<param>/systemd/network/10-</param>
|
||||
<param type="variable">zones_list</param>
|
||||
<param>-risotto.network</param>
|
||||
<param name="join"></param>
|
||||
<param name="multi" type="boolean">True</param>
|
||||
<target>netwokd_configurations</target>
|
||||
</fill>
|
||||
</constraints>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
constraints:
|
||||
- fill:
|
||||
|
|
@ -67,32 +39,3 @@ constraints:
|
|||
target:
|
||||
- text: netwokd_configurations
|
||||
```
|
||||
|
||||
Le contenu de la variable `netwokd_configurations` sera alors :
|
||||
|
||||
- /systemd/netword/10-zone1/risotto.network
|
||||
- /systemd/netword/10-zone2/risotto.network
|
||||
- /systemd/netword/10-zone3/risotto.network
|
||||
|
||||
Enfin déclarer une balise file en utilisant ces deux variables :
|
||||
|
||||
```xml
|
||||
<services>
|
||||
<service name="systemd-networkd">
|
||||
<file file_type="variable" source="network" variable="zones_list">netwokd_configurations</file>
|
||||
</service>
|
||||
</services>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
services:
|
||||
- service:
|
||||
- name: systemd-networkd
|
||||
file:
|
||||
- file_type: variable
|
||||
source: network
|
||||
variable: zones_list
|
||||
text: netwokd_configurations
|
||||
```
|
||||
|
|
|
|||
|
|
@ -4,55 +4,25 @@
|
|||
|
||||
Dans un premier dictionnaire déclarons notre variable et notre calcule :
|
||||
|
||||
```xml
|
||||
<variables>
|
||||
<variable name="my_calculated_variable"/>
|
||||
</variables>
|
||||
<constraints>
|
||||
<fill name="return_no">
|
||||
<target>my_calculated_variable</target>
|
||||
</fill>
|
||||
</constraints>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
variables:
|
||||
- variable:
|
||||
name: my_calculated_variable
|
||||
constraints:
|
||||
- fill:
|
||||
- name: return_no
|
||||
target:
|
||||
- text: my_calculated_variable
|
||||
---
|
||||
version: '1.0'
|
||||
my_calculated_variable:
|
||||
default:
|
||||
type: jinja
|
||||
jinja: '{{ return_no() }}'
|
||||
```
|
||||
|
||||
Dans un second dictionnaire il est possible de redéfinir le calcul :
|
||||
|
||||
```xml
|
||||
<variables>
|
||||
<variable name="my_calculated_variable" redefine="True"/>
|
||||
</variables>
|
||||
<constraints>
|
||||
<fill name="return_yes">
|
||||
<target>my_calculated_variable</target>
|
||||
</fill>
|
||||
</constraints>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
variables:
|
||||
- variable:
|
||||
name: my_calculated_variable
|
||||
redefine: true
|
||||
constraints:
|
||||
- fill:
|
||||
- name: return_yes
|
||||
target:
|
||||
- text: my_calculated_variable
|
||||
---
|
||||
version: '1.0'
|
||||
my_calculated_variable:
|
||||
redefine: true
|
||||
default:
|
||||
type: jinja
|
||||
jinja: '{{ return_yes() }}'
|
||||
```
|
||||
|
||||
Dans ce cas, à aucun moment la fonction "return_no" ne sera exécuté. Seul la fonction "return_yes" le sera.
|
||||
|
|
@ -65,44 +35,21 @@ Dans un second dictionnaire il est possible de supprimer ce calcul.
|
|||
|
||||
Dans un premier dictionnaire déclarons notre variable et notre calcule :
|
||||
|
||||
```xml
|
||||
<variables>
|
||||
<variable name="my_calculated_variable"/>
|
||||
</variables>
|
||||
<constraints>
|
||||
<fill name="return_no">
|
||||
<target>my_calculated_variable"</target>
|
||||
</fill>
|
||||
</constraints>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
variables:
|
||||
- variable:
|
||||
name: my_calculated_variable
|
||||
constraints:
|
||||
- fill:
|
||||
- name: return_no
|
||||
target:
|
||||
- text: my_calculated_variable
|
||||
---
|
||||
version: '1.0'
|
||||
my_calculated_variable:
|
||||
default:
|
||||
type: jinja
|
||||
jinja: '{{ return_no() }}'
|
||||
```
|
||||
|
||||
Dans un second dictionnaire supprimer ce calcul :
|
||||
|
||||
```xml
|
||||
<variables>
|
||||
<variable name="my_calculated_variable" redefine="True" remove_fill="True"/>
|
||||
</variables>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
variables:
|
||||
- variable:
|
||||
name: my_calculated_variable
|
||||
redefine: true
|
||||
remove_fill: true
|
||||
---
|
||||
version: '1.0'
|
||||
my_calculated_variable:
|
||||
redefine: true
|
||||
default: null
|
||||
```
|
||||
|
|
|
|||
|
|
@ -4,28 +4,13 @@
|
|||
|
||||
Créons une variable dont la valeur est retournée par la fonction "return_no" :
|
||||
|
||||
```xml
|
||||
<variables>
|
||||
<variable name="my_calculated_variable"/>
|
||||
</variables>
|
||||
<constraints>
|
||||
<fill name="return_no">
|
||||
<target>my_calculated_variable</target>
|
||||
</fill>
|
||||
</constraints>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
variables:
|
||||
- variable:
|
||||
name: my_calculated_variable
|
||||
constraints:
|
||||
- fill:
|
||||
- name: return_no
|
||||
target:
|
||||
- text: my_calculated_variable
|
||||
---
|
||||
version: '1.0'
|
||||
my_calculated_variable:
|
||||
default:
|
||||
type: jinja
|
||||
jinja: '{{ return_no() }}'
|
||||
```
|
||||
|
||||
Puis créons la fonction "return_no" :
|
||||
|
|
@ -35,50 +20,21 @@ def return_no():
|
|||
return 'no'
|
||||
```
|
||||
|
||||
La [cible (de type variable)](../target/variable.md) du calcul est ici "my_calculated_variable".
|
||||
|
||||
Dans ce cas, la valeur par défaut est la valeur retournée par la fonction (ici "no"), elle sera calculée tant que l'utilisateur n'a pas de spécifié de valeur à cette variable.
|
||||
|
||||
Attention, si une valeur par défaut est définit dans la variable "my_calculated_variable" :
|
||||
|
||||
```xml
|
||||
<variable name="my_calculated_variable">
|
||||
<value>yes</value>
|
||||
</variable>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
variables:
|
||||
- variable:
|
||||
name: my_calculated_variable
|
||||
value:
|
||||
- text: yes
|
||||
```
|
||||
|
||||
Cette valeur par défaut sera complètement ignorée. C'est le calcul qui en définira la valeur.
|
||||
|
||||
Il est possible de définir des [paramètres](../param/README.md) à cette fonction.
|
||||
|
||||
## Variable avec une valeur calculée
|
||||
|
||||
En ajoutant le paramètre "hidden" à "True" dans la variable précédente, l'utilisateur n'aura plus la possibilité de modifié la valeur. La valeur de la variable sera donc systématiquement calculée :
|
||||
|
||||
```xml
|
||||
<variable name="my_calculated_variable" hidden="True"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
variables:
|
||||
- variable:
|
||||
name: my_calculated_variable
|
||||
hidden: true
|
||||
---
|
||||
version: '1.0'
|
||||
my_calculated_variable:
|
||||
hidden: true
|
||||
default:
|
||||
type: jinja
|
||||
jinja: '{{ return_no() }}'
|
||||
```
|
||||
|
||||
Si une condition "hidden_if_in" est spécifié à la variable, la valeur sera modifiable par l'utilisateur si elle n'est pas cachée mais elle sera systèmatiquement calculée (même si elle a déjà était modifiée) si la variable est cachée.
|
||||
C'est également vrai également si hidden est un calcul et que le résultat du calcul est `true`.
|
||||
|
||||
## Variable meneuse ou suiveuse avec valeur calculé
|
||||
|
||||
|
|
@ -90,105 +46,66 @@ Si la variable n'est pas multiple, il ne faut pas que le calcule retourne une li
|
|||
|
||||
Il est également possible de calculer [une variable d'une famille dynamique](../family/auto.md) à partir d'une variable standard :
|
||||
|
||||
```xml
|
||||
<variables>
|
||||
<variable name='suffixes' type='string' description="Suffixes of dynamic family" multi="True">
|
||||
<value>val1</value>
|
||||
<value>val2</value>
|
||||
</variable>
|
||||
<variable name="my_variable" type="string" description="My variable">
|
||||
<value>val</value>
|
||||
</variable>
|
||||
<family name='dyn' dynamic="suffixes">
|
||||
<variable name="my_calculated_variable_dyn_" type="string" description="My calculated variable"/>
|
||||
<value>val</value>
|
||||
</variable>
|
||||
</family>
|
||||
</variables>
|
||||
<constraints>
|
||||
<fill name="return_value">
|
||||
<param type="variable">my_variable</param>
|
||||
<target>my_calculated_variable_dyn_</target>
|
||||
</fill>
|
||||
</constraints>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
variables:
|
||||
- variable:
|
||||
name: suffixes
|
||||
---
|
||||
version: '1.0'
|
||||
suffixes:
|
||||
type: string
|
||||
description: Suffixes of dynamic family
|
||||
multi: true
|
||||
default:
|
||||
- val1
|
||||
- val2
|
||||
my_variable:
|
||||
type: string
|
||||
description: My variable
|
||||
default: val
|
||||
dyn_:
|
||||
type: dynamic
|
||||
variable: rougail.suffixes
|
||||
my_calculated_variable_dyn_:
|
||||
type: string
|
||||
description: Suffixes of dynamic family
|
||||
multi: true
|
||||
value:
|
||||
- text: val1
|
||||
- text: val2
|
||||
- variable:
|
||||
name: my_variable
|
||||
type: string
|
||||
description: My variable
|
||||
value:
|
||||
- text: val
|
||||
- family:
|
||||
name: dyn
|
||||
dynamic: suffixes
|
||||
variables:
|
||||
- variable:
|
||||
name: my_calculated_variable_dyn_
|
||||
type: string
|
||||
description: My calculated variable
|
||||
value:
|
||||
- text: val
|
||||
constraints:
|
||||
- fill:
|
||||
- name: return_value
|
||||
param:
|
||||
- type: variable
|
||||
text: my_variable
|
||||
target:
|
||||
- text: my_calculated_variable_dyn_
|
||||
description: My calculated variable
|
||||
default:
|
||||
type: variable
|
||||
variable: rougail.my_variable
|
||||
```
|
||||
|
||||
Dans ce cas, les variables dynamiques "my_calculated_variable_dyn_" seront calculés à partir de la valeur de la variable "my_variable".
|
||||
Que cela soit pour la variable "my_calculated_variable_dyn_val1" et "my_calculated_variable_dyn_val2".
|
||||
Dans ce cas, les variables dynamiques "rougail.dyn_.my_calculated_variable_dyn_" seront calculés à partir de la valeur de la variable "my_variable".
|
||||
Que cela soit pour la variable "rougail.dynval1.my_calculated_variable_dyn_val1" ou "rougail.dynval2.my_calculated_variable_dyn_val2".
|
||||
|
||||
Par contre, il n'est pas possible de faire un calcul pour une seule des deux variables issues de la variable dynamique.
|
||||
Si c'est ce que vous cherchez à faire, il faudra prévoir un traitement particulier dans votre fonction.
|
||||
|
||||
Dans ce cas, il faut explicitement demander la valeur du suffix dans la fonction :
|
||||
Dans ce cas, il faut explicitement demander le suffix et faire un traitement :
|
||||
|
||||
```xml
|
||||
<constraints>
|
||||
<fill name="return_value_suffix">
|
||||
<param type="variable">my_variable</param>
|
||||
<param type="suffix"/>
|
||||
<target>my_calculated_variable_dyn_</target>
|
||||
</fill>
|
||||
</constraints>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
constraints:
|
||||
- fill:
|
||||
- name: return_value_suffix
|
||||
param:
|
||||
- type: variable
|
||||
text: my_variable
|
||||
- type:suffix
|
||||
target:
|
||||
- text: my_calculated_variable_dyn_
|
||||
```
|
||||
|
||||
Et ainsi faire un traitement spécifique pour ce suffix :
|
||||
|
||||
```python
|
||||
def return_value_suffix(value, suffix):
|
||||
if suffix == 'val1':
|
||||
return value
|
||||
---
|
||||
version: '1.0'
|
||||
suffixes:
|
||||
type: string
|
||||
description: Suffixes of dynamic family
|
||||
multi: true
|
||||
default:
|
||||
- val1
|
||||
- val2
|
||||
my_variable:
|
||||
type: string
|
||||
description: My variable
|
||||
default: val
|
||||
dyn_:
|
||||
type: dynamic
|
||||
variable: rougail.suffixes
|
||||
my_calculated_variable_dyn_:
|
||||
type: string
|
||||
description: My calculated variable
|
||||
default:
|
||||
type: jinja
|
||||
jinja: "{% if suffix == 'val1' %}value{% endif %}"
|
||||
params:
|
||||
suffix:
|
||||
type: suffix
|
||||
```
|
||||
|
||||
## Variable avec valeur calculée obligatoire
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
# Paramètre de la fonction
|
||||
|
||||
- [Paramètre positionnel ou nommée](positional.md)
|
||||
- [Type de paramètre simple](simple.md)
|
||||
- [Type de paramètre "variable"](variable.md)
|
||||
- [Type de paramètre "information"](information.md)
|
||||
|
|
|
|||
|
|
@ -1,41 +0,0 @@
|
|||
# Paramètre positionnel
|
||||
|
||||
Déclarons un paramètre positionnel :
|
||||
|
||||
```xml
|
||||
<param>no</param>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
param:
|
||||
- text: no
|
||||
```
|
||||
|
||||
Créons la fonction correspondante :
|
||||
|
||||
```python
|
||||
def return_value(value):
|
||||
return value
|
||||
```
|
||||
|
||||
La variable "value" de la fonction "return_value" aura donc "no" comme valeur puisque le paramètre aura la valeur fixe "no".
|
||||
|
||||
# Paramètre nommée
|
||||
|
||||
Déclarons maintenant un paramètre nommée :
|
||||
|
||||
```xml
|
||||
<param name="valeur">no</param>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
param:
|
||||
- name: valeur
|
||||
text: no
|
||||
```
|
||||
|
||||
Dans ce cas la fonction return_value sera exécuté avec le paramètre nommé "valeur" dont sa valeur sera "no".
|
||||
|
|
@ -1,90 +1,16 @@
|
|||
# Paramètre de type "texte"
|
||||
# Paramètre de type simple
|
||||
|
||||
Déclarons un paramètre avec une string :
|
||||
|
||||
```xml
|
||||
<param type="string">no</param>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
Déclarons une variable donc la valeur est calculé via un paramètre contenu une valeur :
|
||||
|
||||
```yml
|
||||
param:
|
||||
- type: string
|
||||
text: no
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
default:
|
||||
type: jinja
|
||||
jinja: '{{ value }}'
|
||||
params:
|
||||
value: 'no'
|
||||
```
|
||||
|
||||
C'est le type par défaut pour un paramètre.
|
||||
|
||||
# Paramètre de type "nombre"
|
||||
|
||||
Déclarons un paramètre avec un nombre :
|
||||
|
||||
```xml
|
||||
<param type="number">1</param>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
param:
|
||||
- type: number
|
||||
text: 1
|
||||
```
|
||||
|
||||
Créons la fonction correspondante :
|
||||
|
||||
```python
|
||||
def return_value_with_number(value):
|
||||
if value == 1:
|
||||
return 'no'
|
||||
return 'yes'
|
||||
```
|
||||
|
||||
La variable aura donc "no" comme valeur puisque le paramètre aura la valeur fixe "1".
|
||||
|
||||
# Paramètre de type "booléen"
|
||||
|
||||
Déclarons un paramètre avec un booléen :
|
||||
|
||||
```xml
|
||||
<param type="boolean">True</param>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
param:
|
||||
- type: boolean
|
||||
text: true
|
||||
```
|
||||
|
||||
# Paramètre de type "nil"
|
||||
|
||||
Le paramètre peut être une valeur null (None en python) :
|
||||
|
||||
```xml
|
||||
<param type="nil"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
param:
|
||||
- type: nil
|
||||
```
|
||||
|
||||
# Paramètre de type "space"
|
||||
|
||||
Les paramètres sont chargés en supprimer les espaces en début ou fin de chaîne. Ce qui rend impossible d'avoir un paramètre " ". Avec le type "space", le paramètre sera donc un simple espace :
|
||||
|
||||
```xml
|
||||
<param type="space"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
param:
|
||||
- type: space
|
||||
```
|
||||
La valeur de la variable conserve sont type.
|
||||
|
|
|
|||
|
|
@ -1,43 +1,26 @@
|
|||
# Paramètre de type "variable"
|
||||
|
||||
Imaginons que la variable "my_variable" pré-existe. La valeur de la variable sera utilisé comme paramètre :
|
||||
|
||||
```xml
|
||||
<param type="variable">my_variable</param>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
Il est possible de spécifier le nom d'une variable qui peut ne pas exister :
|
||||
|
||||
```yml
|
||||
param:
|
||||
- type: variable
|
||||
text: my_variable
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
default:
|
||||
type: jinja
|
||||
jinja: |+
|
||||
{% if value %}
|
||||
value
|
||||
{% endif %}
|
||||
params:
|
||||
value:
|
||||
type: variable
|
||||
variable: rougail.unknown_variable
|
||||
optional: true
|
||||
```
|
||||
|
||||
[Les variables meneuses ou suiveuses](../family/leadership.md) peuvent être utilisé sans soucis comme paramètre.
|
||||
|
||||
## Paramètre avec variable potentiellement non existante
|
||||
|
||||
Suivant le contexte une variable peut exister ou ne pas exister.
|
||||
|
||||
Un paramètre de type "variable" peut être "optional" :
|
||||
|
||||
```xml
|
||||
<param type="variable" optional="True">unknow_variable</param>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
param:
|
||||
- type: variable
|
||||
optional: true
|
||||
text: unknow_variable
|
||||
```
|
||||
|
||||
Si la variable "unknow_variable" n'existe pas, le paramètre ne sera pas passé à la fonction.
|
||||
|
||||
Si maintenant on créé un nouveau dictionnaire en créant cette variable, la fonction sera exécuté avec le paramètre.
|
||||
La variable "rougail.unknown_variable" n'existant, `value` sera égal à `None` et la valeur de la variable "rougail.my_variable" sera aussi égale à `None`.
|
||||
Si "rougail.unknown_variable" est créé dans un autre dictionnaire, sa valeur sera ainsi copié.
|
||||
|
||||
## Paramètre avec variable potentiellement désactivée
|
||||
|
||||
|
|
@ -45,17 +28,23 @@ Si une variable est désactivé, l'utilisation de cette variable peut poser prob
|
|||
|
||||
Il est possible de ne pas générer d'erreur si une variable est désactivé en utilisant le paramètre "propertyerror" :
|
||||
|
||||
```xml
|
||||
<param type="variable" propertyerror="False">variable1</param>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
param:
|
||||
- type: variable
|
||||
propertyerror: false
|
||||
text: variable1
|
||||
---
|
||||
version: '1.0'
|
||||
disabled_variable:
|
||||
disabled: true
|
||||
my_variable:
|
||||
default:
|
||||
type: jinja
|
||||
jinja: |+
|
||||
{% if value is defined and value %}
|
||||
value
|
||||
{% endif %}
|
||||
params:
|
||||
value:
|
||||
type: variable
|
||||
variable: rougail.disabled_variable
|
||||
propertyerror: false
|
||||
```
|
||||
|
||||
Dans ce cas, si la variable est désactivé, le paramètre n'est jamais donnée à la fonction de destination.
|
||||
|
|
@ -66,18 +55,110 @@ Il est possible de faire un calcul avec comme paramètre [une variable d'une fam
|
|||
|
||||
Par exemple :
|
||||
|
||||
```xml
|
||||
<param type="variable">vardynval1</param>
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
varname:
|
||||
multi: true
|
||||
default:
|
||||
- val1
|
||||
- val2
|
||||
my_dyn_family_:
|
||||
type: dynamic
|
||||
variable: rougail.varname
|
||||
description: 'Describe '
|
||||
my_dyn_var_:
|
||||
type: string
|
||||
default: "val"
|
||||
my_variable:
|
||||
multi: true
|
||||
unique: false
|
||||
default:
|
||||
type: jinja
|
||||
jinja: |+
|
||||
{% for val in value %}
|
||||
{{ val }}
|
||||
{% endfor %}
|
||||
params:
|
||||
value:
|
||||
type: variable
|
||||
variable: rougail.my_dyn_family_.my_dyn_var_
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
param:
|
||||
- type: variable
|
||||
text: vardynval1
|
||||
---
|
||||
version: '1.0'
|
||||
varname:
|
||||
multi: true
|
||||
default:
|
||||
- val1
|
||||
- val2
|
||||
my_dyn_family_:
|
||||
type: dynamic
|
||||
variable: rougail.varname
|
||||
description: 'Describe '
|
||||
my_dyn_var_:
|
||||
type: string
|
||||
default: "val"
|
||||
my_variable:
|
||||
default:
|
||||
type: jinja
|
||||
jinja: |+
|
||||
{% if value is defined and value %}
|
||||
{{ value }}
|
||||
{% endif %}
|
||||
params:
|
||||
value:
|
||||
type: variable
|
||||
variable: rougail.my_dyn_family_val1.my_dyn_var_val1
|
||||
```
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
varname:
|
||||
multi: true
|
||||
default:
|
||||
- val1
|
||||
- val2
|
||||
my_dyn_family_:
|
||||
type: dynamic
|
||||
variable: rougail.varname
|
||||
description: 'Describe '
|
||||
my_dyn_var_:
|
||||
type: string
|
||||
default:
|
||||
type: jinja
|
||||
jinja: '{{ value }}'
|
||||
params:
|
||||
value:
|
||||
type: suffix
|
||||
```
|
||||
|
||||
PAS LE BON FICHIER :
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
varname:
|
||||
multi: true
|
||||
default:
|
||||
- val1
|
||||
- val2
|
||||
my_dyn_family_:
|
||||
type: dynamic
|
||||
variable: rougail.varname
|
||||
description: 'Describe '
|
||||
my_dyn_var_:
|
||||
type: string
|
||||
default:
|
||||
type: suffix
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Dans ce cas, la valeur du paramètre de la fonction sera la valeur de la variable "vardyn" pour la famille ayant le suffix "val1".
|
||||
|
||||
Il peut être utile de récupérer la valeur du suffix dans la fonction, pour cela il suffit de mettre un paramètre de type suffix :
|
||||
|
|
|
|||
|
|
@ -1,186 +0,0 @@
|
|||
# La gestion d'un service
|
||||
|
||||
## La base service
|
||||
|
||||
Un service est inclut dans un conteneur [services](../services.md).
|
||||
|
||||
Cette balise permet de définir tous les éléments ([fichier](file.md), [certificat](certificate.md), [IP](ip.md) et [réécriture](override.md)) liés à un service ou à démon.
|
||||
|
||||
Il faut, à la création du service, préciser son nom :
|
||||
|
||||
```xml
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<rougail version="0.10">
|
||||
<services>
|
||||
<service name="squid"/>
|
||||
</services>
|
||||
</rougail>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
version: '0.10'
|
||||
services:
|
||||
- service:
|
||||
- name: squid
|
||||
```
|
||||
|
||||
## Les types de service
|
||||
|
||||
Les services peuvent être de plusieurs type :
|
||||
|
||||
- service (valeur par défaut) : cela signifie que c'est un service systemd qui est activer au démarrage de la machine
|
||||
- mount : fichier utilisé par systemd-mount
|
||||
- swap : fichier utilisé par systemd-swap
|
||||
- timer : tâche planifié pour systemd
|
||||
|
||||
```xml
|
||||
<service name="dev-disk-by\x2dpartlabel-swap" type="swap"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- service:
|
||||
- name: dev-disk-by\x2dpartlabel-swap
|
||||
type: swap
|
||||
```
|
||||
|
||||
## Les targets de service
|
||||
|
||||
Active le service systemd pour une target systemd déterminé. Par défaut, l'activation du service n'est pas gérer par rougail.
|
||||
|
||||
```xml
|
||||
<service name="squid" target="multi-user"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- service:
|
||||
- name: squid
|
||||
target: multi-user
|
||||
```
|
||||
|
||||
## La génération du fichier service
|
||||
|
||||
Le fichier de description du service peut être fourni directement par la distribution GNU/Linux utilisé, mais il peut également être fournit par l'administrateur.
|
||||
Dans ce cas, il est possible de créé un template, dont le nom est obligatoirement la valeur de la balise "name" + "." + la valeur de la base "type".
|
||||
|
||||
Deux types de template sont aujourd'hui disponible :
|
||||
|
||||
- cheetah
|
||||
- jinja
|
||||
|
||||
```xml
|
||||
<service name="dev-disk-by\x2dpartlabel-swap" type="swap" engine="cheetah"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- service:
|
||||
- name: dev-disk-by\x2dpartlabel-swap
|
||||
type: swap
|
||||
engine: cheetah
|
||||
```
|
||||
|
||||
Dans ce cas, rougail utilisera le template "dev-disk-by\x2dpartlabel-swap.swap" pour générer le fichier systemd de gestion de ce service.
|
||||
|
||||
## Le service factice
|
||||
|
||||
Un service peut être factice, donc non géré par le système de service du système :
|
||||
|
||||
```xml
|
||||
<service name="ldap_client" manage="False"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- service:
|
||||
- name: ldap_client
|
||||
manage: false
|
||||
```
|
||||
|
||||
Un service factice est généralement une service qui n'existe pas réellement (par exemple si on configure un client). Il n'est là que pour contenir des fichiers.
|
||||
|
||||
## Désactiver le service
|
||||
|
||||
Il est possible de désactiver un service. Pour cela il faut rajouter l'attribut "disabled" à True :
|
||||
|
||||
```xml
|
||||
<service name="test" disabled="True"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- service:
|
||||
- name: test
|
||||
disabled: true
|
||||
```
|
||||
|
||||
Dans ce cas, le service et les éléments qu'il compose ([fichier](file.md), [certificat](certificate.md), [IP](ip.md) et [réécriture](override.md) seront désactivés.
|
||||
|
||||
Il est possible de définir une [condition](../condition/README.md) de type "disabled_if_in" ou "disabled_if_not_in" sur une balise service :
|
||||
|
||||
```xml
|
||||
<services>
|
||||
<service name="test" servicelist="test">
|
||||
</service>
|
||||
</services>
|
||||
<variables>
|
||||
<variable name="condition" type="boolean"/>
|
||||
</variables>
|
||||
<constraints>
|
||||
<condition name="disabled_if_in" source="condition">
|
||||
<param>False</param>
|
||||
<target type="servicelist">test</target>
|
||||
</condition>
|
||||
</constraints>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
services:
|
||||
- service:
|
||||
- name: test
|
||||
servicelist: test
|
||||
variables:
|
||||
- variable:
|
||||
- name: condition
|
||||
type: boolean
|
||||
constraints:
|
||||
- condition:
|
||||
- name: disabled_if_in
|
||||
source: condition
|
||||
param:
|
||||
- text: false
|
||||
target:
|
||||
- type: servicelist
|
||||
text: test
|
||||
```
|
||||
|
||||
Dans ce cas, tous les services et les éléments qu'il compose avec un attribut servicelist à "test" seront désactivés si la variable "condition" est False.
|
||||
|
||||
## Ne pas désactiver le service dans systemd
|
||||
|
||||
La désactivation du service va créé un lien symbolique vers /dev/null.
|
||||
|
||||
Si vous ne voulez juste pas créer le fichier de service et ne pas faire de lien symbolique, il faut utiliser l'attribut undisable :
|
||||
|
||||
```xml
|
||||
<service name="test" disabled="True" undisable="True"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- service:
|
||||
- name: test
|
||||
disabled: true
|
||||
undisable: true
|
||||
```
|
||||
|
|
@ -1,163 +0,0 @@
|
|||
# La gestion d'un certificat
|
||||
|
||||
## La balise certificate
|
||||
|
||||
La gestion des certificats se fait dans un conteneur de [service](README.md).
|
||||
|
||||
La déclaration du certificat permet d'associer un certificat à un service. Attention, Rougail ne permet que de déclarer ces certificats. Il n'y a pas de gestion du certification dans la bibliothèque.
|
||||
|
||||
Pour déclarer un certificat :
|
||||
|
||||
```xml
|
||||
<services>
|
||||
<service name="squid">
|
||||
<certificate private="/etc/pki/tls/private/squid.key" authority="/etc/pki/ca-trust/source/anchors/ca_squid.crt">/etc/pki/tls/certs/squid.crt</certificate>
|
||||
</service>
|
||||
</services>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
services:
|
||||
- service:
|
||||
- name: squid
|
||||
certificate:
|
||||
- private: /etc/pki/tls/private/squid.key
|
||||
authority: /etc/pki/ca-trust/source/anchors/ca_squid.crt
|
||||
text: /etc/pki/tls/certs/squid.crt
|
||||
```
|
||||
|
||||
Les trois informations a donner sont donc :
|
||||
|
||||
- le nom du certificat
|
||||
- le nom de la clef privée
|
||||
- le nom de certificat de l'autorité de certification
|
||||
|
||||
## Les noms de fichiers dynamique
|
||||
|
||||
Il est possible également de définir le nom des fichiers dans des variables :
|
||||
|
||||
```xml
|
||||
<services>
|
||||
<service name="squid">
|
||||
<certificate private="private" private_type="variable" authority="authority" authority_type="variable" certificate_type="variable">certificate</certificate>
|
||||
</service>
|
||||
</services>
|
||||
<variables>
|
||||
<variable name="certificate" type="filename">
|
||||
<value>/etc/pki/tls/certs/squid.crt</value>
|
||||
</variable>
|
||||
<variable name="private" type="filename">
|
||||
<value>/etc/pki/tls/private/squid.key</value>
|
||||
</variable>
|
||||
<variable name="authority" type="filename">
|
||||
<value>/etc/pki/ca-trust/source/anchors/ca_squid.crt</value>
|
||||
</variable>
|
||||
</variables>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
services:
|
||||
- service:
|
||||
- name: squid
|
||||
certificate:
|
||||
- private: private
|
||||
private_type: variable
|
||||
authority: authority
|
||||
authority_type: variable
|
||||
certificate_type: variable
|
||||
text: certificate
|
||||
variables:
|
||||
- variable:
|
||||
- name: certificate
|
||||
type: filename
|
||||
value:
|
||||
- text: /etc/pki/tls/certs/squid.crt
|
||||
- name: private
|
||||
type: filename
|
||||
value:
|
||||
- text: /etc/pki/tls/private/squid.key
|
||||
- name: authority
|
||||
type: filename
|
||||
value:
|
||||
- text: /etc/pki/ca-trust/source/anchors/ca_squid.crt
|
||||
```
|
||||
|
||||
Attention, les variables doivent être de type "filename".
|
||||
|
||||
## Le propriétaire de la clef privée
|
||||
|
||||
Le certificat et le certificat de l'autorité de certification n'ont pas besoin d'être privés.
|
||||
Par contre, seul le service qui doit avoir accès à la clef privée.
|
||||
|
||||
Par défaut seul utilisateur "root" et groupe "root" peuvent y accéder.
|
||||
|
||||
Il est possible de définir l'utilisateur ou le groupe de la clef privée générée :
|
||||
|
||||
```xml
|
||||
<services>
|
||||
<service name="squid">
|
||||
<certificate private="/etc/pki/tls/private/squid.key" authority="/etc/pki/ca-trust/source/anchors/ca_squid.crt" owner="squid" group="squid">/etc/pki/tls/certs/squid.crt</certificate>
|
||||
</service>
|
||||
</services>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
services:
|
||||
- service:
|
||||
- name: squid
|
||||
certificate:
|
||||
- private: /etc/pki/tls/private/squid.key
|
||||
authority: /etc/pki/ca-trust/source/anchors/ca_squid.crt
|
||||
owner: squid
|
||||
group: squid
|
||||
text: /etc/pki/tls/certs/squid.crt
|
||||
```
|
||||
|
||||
L'utilisateur et le groupe peuvent être défini dans une variable :
|
||||
|
||||
```xml
|
||||
<services>
|
||||
<service name="squid">
|
||||
<certificate private="/etc/pki/tls/private/squid.key" authority="/etc/pki/ca-trust/source/anchors/ca_squid.crt" owner="owner" owner_type="variable" group="group" group_type="variable">/etc/pki/tls/certs/squid.crt</certificate>
|
||||
</service>
|
||||
<variables>
|
||||
<variable name="owner" type="unix_user">
|
||||
<value>squid</value>
|
||||
</variable>
|
||||
<variable name="group" type="unix_user">
|
||||
<value>squid</value>
|
||||
</variable>
|
||||
</services>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
services:
|
||||
- service:
|
||||
- name: squid
|
||||
certificate:
|
||||
- private: /etc/pki/tls/private/squid.key
|
||||
authority: /etc/pki/ca-trust/source/anchors/ca_squid.crt
|
||||
owner: owner
|
||||
owner_type: variable
|
||||
group: group
|
||||
group_type: variable
|
||||
text: /etc/pki/tls/certs/squid.crt
|
||||
variables:
|
||||
- variable:
|
||||
- name: owner
|
||||
type: unix_user
|
||||
value:
|
||||
- text: squid
|
||||
- name: group
|
||||
type: unix_user
|
||||
value:
|
||||
- text: squid
|
||||
```
|
||||
|
|
@ -1,454 +0,0 @@
|
|||
# La gestion d'un fichier
|
||||
|
||||
## La balise file
|
||||
|
||||
La gestion des fichiers se fait dans un conteneur de [service](README.md).
|
||||
|
||||
La déclaration du fichier permet de générer un fichier à partir d'un template pour le déposer à l'endroit prévu dans la déclaration de cette élément.
|
||||
|
||||
Il est nécessaire, au minimum, de spécifier le chemin complet du fichier :
|
||||
|
||||
```xml
|
||||
<services>
|
||||
<service name="squid">
|
||||
<file>/etc/squid/squid.conf</file>
|
||||
</service>
|
||||
</services>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
services:
|
||||
- service:
|
||||
- name: squid
|
||||
file:
|
||||
- text: /etc/squid/squid.conf
|
||||
```
|
||||
|
||||
## Le nom de template
|
||||
|
||||
Par défaut, le nom du template est déduit du nom du fichier.
|
||||
|
||||
Par xemple, si le fichier de destination est "/etc/squid/squid.conf", le template aura le nom "squid.conf".
|
||||
|
||||
Si le template a un nom différent (par exemple si plusieurs template se retrouve avec le même nom), il est possible de changer le nom du template avec l'attribut source :
|
||||
|
||||
```xml
|
||||
<file source="template-squid.conf">/etc/squid/squid.conf</file>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
file:
|
||||
- source: template-squid.conf
|
||||
text: /etc/squid/squid.conf
|
||||
```
|
||||
|
||||
## Le nom de template dynamique
|
||||
|
||||
La source peut ếgalement être une variable :
|
||||
|
||||
```xml
|
||||
<services>
|
||||
<service name="squid">
|
||||
<file source="source_var" source_type="variable">/etc/squid/squid.conf</file>
|
||||
</service>
|
||||
</services>
|
||||
<variables>
|
||||
<variable name="source_var">
|
||||
<value>template-squid.conf</value>
|
||||
</variable>
|
||||
</variables>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
services:
|
||||
- service:
|
||||
- name: squid
|
||||
file:
|
||||
- source: source_var
|
||||
source_type: variable
|
||||
text: /etc/squid/squid.conf
|
||||
variables:
|
||||
- variable:
|
||||
- name: source_var
|
||||
value:
|
||||
- text: template-squid.conf
|
||||
```
|
||||
|
||||
## Les noms de fichiers dynamique
|
||||
|
||||
Il est possible également de définir le nom du fichier dans une variable :
|
||||
|
||||
```xml
|
||||
<services>
|
||||
<service name="squid">
|
||||
<file file_type="variable" source="squid.conf">my_variable</file>
|
||||
</service>
|
||||
</services>
|
||||
<variables>
|
||||
<variable name="my_variable">
|
||||
<value>/etc/squid/squid.conf</value>
|
||||
</variable>
|
||||
</variables>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
services:
|
||||
- service:
|
||||
- name: squid
|
||||
file:
|
||||
- file_type: variable
|
||||
source: squid.conf
|
||||
text: my_variable
|
||||
variables:
|
||||
- variable:
|
||||
name: my_variable
|
||||
value:
|
||||
- text: /etc/squid/squid.conf
|
||||
```
|
||||
|
||||
Attention, la variable doit être de type "filename".
|
||||
|
||||
Dans le cas des fichiers dynamique, la source est obligatoire.
|
||||
|
||||
Il est même possible de définir une variable de type multiple, ce qui génèrera plusiers fichiers :
|
||||
|
||||
```xml
|
||||
<services>
|
||||
<service name="squid">
|
||||
<file file_type="variable" source="squid.conf">my_variable</file>
|
||||
</service>
|
||||
</services>
|
||||
<variables>
|
||||
<variable name="my_variable" multi="True">
|
||||
<value>/etc/squid1/squid.conf</value>
|
||||
<value>/etc/squid2/squid.conf</value>
|
||||
</variable>
|
||||
</variables>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
services:
|
||||
- service:
|
||||
- name: squid
|
||||
file:
|
||||
- file_type: variable
|
||||
source: squid.conf
|
||||
text: my_variable
|
||||
variables:
|
||||
- variable:
|
||||
name: my_variable
|
||||
multi: true
|
||||
value:
|
||||
- text: /etc/squid1/squid.conf
|
||||
- text: /etc/squid2/squid.conf
|
||||
```
|
||||
|
||||
Dans ce cas là, le fichier source est identique mais les fichiers de destination seront différent.
|
||||
|
||||
Il peut être important de personnaliser le contenu du fichier suivant le fichier de destination.
|
||||
Dans ce cas il y a deux possibilités :
|
||||
|
||||
- la variable "rougail_filename" contient le nom de fichier de destination
|
||||
- l'utilisateur de l'attribut "variable"
|
||||
|
||||
En effet, il est possible de passer le contenu d'une variable au template :
|
||||
|
||||
```xml
|
||||
<services>
|
||||
<service name="squid">
|
||||
<file file_type="variable" source="squid.conf" variable="my_variable2">my_variable1</file>
|
||||
</service>
|
||||
</services>
|
||||
<variables>
|
||||
<variable name="my_variable1" multi="True">
|
||||
<value>/etc/squid1/squid.conf</value>
|
||||
<value>/etc/squid2/squid.conf</value>
|
||||
</variable>
|
||||
<variable name="my_variable2" multi="True">
|
||||
<value>squid1</value>
|
||||
<value>squid2</value>
|
||||
</variable>
|
||||
</variables>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
services:
|
||||
- service:
|
||||
- name: squid
|
||||
file:
|
||||
- file_type: variable
|
||||
source: squid.conf
|
||||
variable: my_variable2
|
||||
text: my_variable1
|
||||
variables:
|
||||
- variable:
|
||||
name: my_variable1
|
||||
multi: true
|
||||
value:
|
||||
- text: /etc/squid1/squid.conf
|
||||
- text: /etc/squid2/squid.conf
|
||||
- variable:
|
||||
name: my_variable2
|
||||
multi: true
|
||||
value:
|
||||
- text: squid1
|
||||
- text: squid2
|
||||
```
|
||||
|
||||
Dans ce cas, lors de la génération du fichier /etc/squid1/squid.conf on retrouvera la variable "rougail_variable" avec la valeur "squid1" et la variable "rougail_index" avec la valeur "0". Lors de la génération du fichier /etc/squid2/squid.conf on retrouvera la variable "rougail_variable" avec la valeur "squid2" et la variable "rougail_index" avec la valeur "1".
|
||||
|
||||
Attention : les deux variables "my_variable1" et "my_variable2" doivent être multiple et de même longueur.
|
||||
|
||||
## Les droits des fichiers
|
||||
|
||||
Par défaut les droits du fichier généré sont "0644" avec comme utilisateur "root" et groupe "root".
|
||||
|
||||
Il est possible de définir les droits, l'utilisateur ou le groupe d'un fichier généré :
|
||||
|
||||
```xml
|
||||
<file mode="0640" owner="nobody" group="squid">/etc/squid/squid.conf</file>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
file:
|
||||
- mode: '0640'
|
||||
owner: nobody
|
||||
group: squid
|
||||
text: /etc/squid/squid.conf
|
||||
```
|
||||
|
||||
Il est possible de personnaliser les droits par défaut dans la [configuration de rougail](../dev/config.md)
|
||||
|
||||
## Désactiver la génération d'un fichier
|
||||
|
||||
Il est possible de désactiver la génération d'un fichier avec l'attribut "disabled" :
|
||||
|
||||
```xml
|
||||
<file disabled="True">/etc/squid/squid.conf</file>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
file:
|
||||
- disabled: true
|
||||
text: /etc/squid/squid.conf
|
||||
```
|
||||
|
||||
Il est aussi possible de définir une [condition](../condition/README.md) de type "disabled_if_in" ou "disabled_if_not_in" sur une balise fichier :
|
||||
|
||||
```xml
|
||||
<services>
|
||||
<service name="test">
|
||||
<file filelist="squid">/etc/squid/squid.conf</file>
|
||||
</service>
|
||||
</services>
|
||||
<variables>
|
||||
<variable name="condition" type="boolean"/>
|
||||
</variables>
|
||||
<constraints>
|
||||
<condition name="disabled_if_in" source="condition">
|
||||
<param>False</param>
|
||||
<target type="filelist">squid</target>
|
||||
</condition>
|
||||
</constraints>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
services:
|
||||
- service:
|
||||
- name: text
|
||||
file:
|
||||
- filelist: squid
|
||||
text: /etc/squid/squid.conf
|
||||
variables:
|
||||
- variable:
|
||||
name: condition
|
||||
type: boolean
|
||||
constraints:
|
||||
- condition:
|
||||
- name: disabled_if_in
|
||||
source: condition
|
||||
param:
|
||||
- text: false
|
||||
target:
|
||||
- type: filelist
|
||||
text: squid
|
||||
```
|
||||
|
||||
Dans ce cas, tous les fichiers avec un attribut filelist à "squid" seront désactivés si la variable "condition" est False.
|
||||
|
||||
## Redéfinir une fichier
|
||||
|
||||
Il est possible de redéfinir les éléments d'un fichier dans un dictionnaire différent en utilisant l'attribut redefine :
|
||||
|
||||
```xml
|
||||
<file source="template-squid.conf" redefine="True">/etc/squid/squid.conf</file>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
file:
|
||||
- source: template-squid.conf
|
||||
redefine: true
|
||||
text: /etc/squid/squid.conf
|
||||
```
|
||||
|
||||
## Choix du moteur de templating
|
||||
|
||||
Par défaut, le moteur de templating est le moteur de templating compatible avec "cheetah".
|
||||
|
||||
Il est possible de désactiver la templatisation du fichier (il sera alors uniquement copié) :
|
||||
|
||||
```xml
|
||||
<file engine="none">/etc/squid/squid.conf</file>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
file:
|
||||
- engine: 'none'
|
||||
text: /etc/squid/squid.conf
|
||||
```
|
||||
|
||||
Ou d'utiliser le moteur "jinja" :
|
||||
|
||||
```xml
|
||||
<file engine="jinja">/etc/squid/squid.conf</file>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
file:
|
||||
- engine: jinja
|
||||
text: /etc/squid/squid.conf
|
||||
```
|
||||
|
||||
Il est possible de personnaliser le moteur par défaut dans la [configuration de rougail](../dev/config.md)
|
||||
|
||||
## Inclusion de template
|
||||
|
||||
Un attribut "included" permet de définir la nature du fichier. Cet attribut peut avoir trois valeurs :
|
||||
|
||||
- "no" : c'est un fichier normal
|
||||
- "name" : le répertoire de destination est listé dans un autre template, il faut que le fichier soit généré avant cet autre template
|
||||
- "content" : le contenu du fichier est copié dans un autre template, il faut que le fichier soit généré avant cet autre template et ce fichier n'a pas besoin d'être installé sur le serveur cible.
|
||||
|
||||
Bien entendu, c'est au développeur de lister ou d'inclure le contenu de ce template dans le fichier de destination. Cet attribut permet juste de garantir que le fichier sera fait avant l'autre et de ne pas l'installer sur le serveur si ce n'est pas nécessaire.
|
||||
|
||||
Il est possible de personnaliser les methodes d'inclusion par défaut dans la [configuration de rougail](../dev/config.md)
|
||||
|
||||
Exemples :
|
||||
|
||||
- créons un template qui inclut des noms de fichiers :
|
||||
|
||||
Le contenu de ce template (squid.conf) est :
|
||||
|
||||
```
|
||||
%import os
|
||||
%set %%confdir = 'etc/squid/squid.d/'
|
||||
%if %%os.path.exists(%%confdir)
|
||||
%set %%files = %%os.listdir(%%confdir)
|
||||
%%files.sort()
|
||||
%for %%file in %%files
|
||||
%if %%file.endswith('.cfg')
|
||||
include '/' + %%confdir + file
|
||||
%end if
|
||||
%end for
|
||||
%end if
|
||||
```
|
||||
|
||||
Ajoutons un second template (squid.included.conf) qui sera copié dans ce répertoire :
|
||||
|
||||
```
|
||||
template content
|
||||
```
|
||||
|
||||
Et déclaront ces deux templates :
|
||||
|
||||
```xml
|
||||
<file>/etc/squid/squid.conf</file>
|
||||
<file included="name" engine="none">/etc/squid/squid.d/squid.conf</file>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
file:
|
||||
- text: /etc/squid/squid.conf
|
||||
- included: name
|
||||
engine: 'none'
|
||||
text: /etc/squid/squid.d/squid.conf
|
||||
```
|
||||
|
||||
Le contenu du fichier généré (/etc/squid/squid.conf) sera donc :
|
||||
|
||||
```
|
||||
include squid.d/squid.conf
|
||||
```
|
||||
|
||||
- créons un template qui inclut le contenu de fichiers :
|
||||
|
||||
Le contenu de ce template (squid.conf) est :
|
||||
|
||||
```
|
||||
%import os
|
||||
%set %%confdir = 'squid.d/'
|
||||
%if %%os.path.exists(%%confdir)
|
||||
%set %%files = %%os.listdir(%%confdir)
|
||||
%%files.sort()
|
||||
%for %%file in %%files
|
||||
%if %%file.endswith('.cfg')
|
||||
%include raw %%confdir + file
|
||||
%end if
|
||||
%end for
|
||||
%end if
|
||||
```
|
||||
|
||||
Ajoutons un second template (squid.included.conf) qui sera copié dans ce répertoire :
|
||||
|
||||
```
|
||||
template content
|
||||
```
|
||||
|
||||
Et déclaront ces deux templates :
|
||||
|
||||
```xml
|
||||
<file>/etc/squid/squid.conf</file>
|
||||
<file included="content" engine="none">squid.d/squid.conf</file>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
file:
|
||||
- text: /etc/squid/squid.conf
|
||||
- included: content
|
||||
engine: 'none'
|
||||
text: squid.d/squid.conf
|
||||
```
|
||||
|
||||
Le contenu du fichier généré (/etc/squid/squid.conf) sera donc maintenant :
|
||||
|
||||
```
|
||||
template content
|
||||
```
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
# La gestion d'une IP
|
||||
|
||||
## La balise IP
|
||||
|
||||
La gestion des IP se fait dans un conteneur de [service](README.md).
|
||||
|
||||
La déclaration de l'attribut permet d'associer une IP autorisé à accéder au service.
|
||||
|
||||
Il est nécessaire, au minimum, de spécifier le nom d'une variable de type "IP" :
|
||||
|
||||
```xml
|
||||
<ip ip_type="variable">variable_ip</ip>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
ip:
|
||||
- ip_type: variable_ip
|
||||
text: variable_ip
|
||||
```
|
||||
|
||||
## La gestion d'un réseau
|
||||
|
||||
L'adresse peut être de type réseau ("network") :
|
||||
|
||||
```xml
|
||||
<ip netmask="variable_netmask">variable_ip</ip>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
ip:
|
||||
- netmask: variable_netmask
|
||||
text: variable_ip
|
||||
```
|
||||
|
||||
Attention, dans ce cas il faut préciser une variable de type "netmask" dans l'attribut netmask.
|
||||
|
||||
## Désactiver la génération d'une IP
|
||||
|
||||
Il est possible de définir une [condition](../condition/README.md) de type "disabled_if_in" ou "disabled_if_not_in" sur une balise IP :
|
||||
|
||||
```xml
|
||||
<services>
|
||||
<service name="test">
|
||||
<ip iplist="test_ip">variable_ip</ip>
|
||||
</service>
|
||||
</services>
|
||||
<variables>
|
||||
<variable name="condition" type="boolean"/>
|
||||
<variable name="variable_ip" type="ip"/>
|
||||
</variables>
|
||||
<constraints>
|
||||
<condition name="disabled_if_in" source="condition">
|
||||
<param>False</param>
|
||||
<target type="iplist">test_ip</target>
|
||||
</condition>
|
||||
</constraints>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
services:
|
||||
- service:
|
||||
- name: test
|
||||
ip:
|
||||
- iplist: test_ip
|
||||
text: variable_ip
|
||||
variables:
|
||||
- variable:
|
||||
name: condition
|
||||
type: boolean
|
||||
- variable:
|
||||
name: variable_ip
|
||||
type: ip
|
||||
constraints:
|
||||
- condition:
|
||||
- name: disabled_if_in
|
||||
source: condition
|
||||
param:
|
||||
- text: false
|
||||
target:
|
||||
- type: iplist
|
||||
text: test_ip
|
||||
|
||||
```
|
||||
|
||||
Dans ce cas, tous les IP avec un attribut iplist à "test_ip" seront désactivé si la variable "condition" est False.
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
# Réécriture du service
|
||||
|
||||
## La balise override
|
||||
|
||||
La gestion des overrides se fait dans un conteneur de [service](README.md).
|
||||
|
||||
La balise override permet de redéfinir facilement un service systemd.
|
||||
|
||||
Il suffit d'avoir un template dont le nom est par défaut le nom du service avec l'extension "service" et de déclarer la balise :
|
||||
|
||||
```xml
|
||||
<services>
|
||||
<service name="squid">
|
||||
<override/>
|
||||
</service>
|
||||
</services>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
services:
|
||||
- service:
|
||||
- name: squid
|
||||
override: null
|
||||
```
|
||||
|
||||
Dans cette exemple, le template associé doit s'appeler squid.service
|
||||
|
||||
Si le fichier service a un nom différent (par exemple si plusieurs template se retrouve avec le même nom), il est possible de changer le nom du template avec l'attribut source :
|
||||
|
||||
```xml
|
||||
<override source="test.service"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
override:
|
||||
- source: test.service
|
||||
```
|
||||
|
||||
Dans ce cas le fichier de destination aura le même nom.
|
||||
|
||||
## Choix du moteur de templating
|
||||
|
||||
Par défaut, le moteur de templating est le moteur de templating compatible avec "cheetah".
|
||||
|
||||
Il est possible de désactiver la templatisation du fichier (il sera alors uniquement copié) :
|
||||
|
||||
```xml
|
||||
<override engine="none"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
override:
|
||||
- engine: 'none'
|
||||
```
|
||||
|
||||
Ou d'utiliser le moteur "jinja" :
|
||||
|
||||
```xml
|
||||
<override engine="jinja"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
override:
|
||||
- engine: 'jinja'
|
||||
```
|
||||
|
||||
Il est possible de personnaliser le moteur par défaut dans la [configuration de rougail](../dev/config.md)
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
# Le conteneur des services
|
||||
|
||||
La balise "services" est le conteneur de l'ensemble des [services](service/README.md).
|
||||
|
||||
Il est placé à la racine du dictionnaire :
|
||||
|
||||
```xml
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<rougail>
|
||||
<services/>
|
||||
</rougail>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
version: '0.10'
|
||||
services: none
|
||||
```
|
||||
|
||||
Attention, cette balise ne peut pas être placé dans un dictionnaire "extra".
|
||||
103
doc/template/README.md
vendored
103
doc/template/README.md
vendored
|
|
@ -1,103 +0,0 @@
|
|||
# Les templates
|
||||
|
||||
## Le moteur "cheetah"
|
||||
|
||||
Le moteur de templating par défaut est le moteur [Cheetah](https://cheetahtemplate.org/).
|
||||
|
||||
Par contre, la configuration par défaut de Cheetah a été modifié.
|
||||
|
||||
Dans un template de configuration, il est très fréquent que le caractère "#" est le caractère des commentaires.
|
||||
C'est pourquoi la configuration par défaut a été modifié.
|
||||
|
||||
Les choix sont maintenant les suivants :
|
||||
|
||||
- le caractère des directives : "%" ;
|
||||
- les variables : "%%" ;
|
||||
- le caractère des commentaires : "#".
|
||||
|
||||
Voici quelques exemples d'utilisateurs de ce moteur :
|
||||
|
||||
### utiliser une variable
|
||||
|
||||
```
|
||||
%%variable_name
|
||||
```
|
||||
|
||||
### condition
|
||||
|
||||
```
|
||||
%if %%variable_name == 'oui'
|
||||
text
|
||||
%end if
|
||||
```
|
||||
|
||||
### vérifier si une variable existe
|
||||
|
||||
```
|
||||
%if %%varExists('variable_name')
|
||||
text
|
||||
%end if
|
||||
```
|
||||
|
||||
### boucle
|
||||
|
||||
```
|
||||
%for %%var in %%variable_name
|
||||
%%var
|
||||
%end for
|
||||
```
|
||||
|
||||
### boucle avec variables meneuse et suiveuse
|
||||
|
||||
```
|
||||
%for %%var in %%variable_leader
|
||||
%%var.variable_follower
|
||||
%end for
|
||||
```
|
||||
|
||||
Pour plus d'informations, voir la documentation de Cheetah.
|
||||
|
||||
## Le moteur "jinja"
|
||||
|
||||
Il est possible d'utiliser le moteur de templating [Jinja](https://jinja.palletsprojects.com/).
|
||||
|
||||
Il n'y a pas d'adaptation particulière pour ce moteur.
|
||||
|
||||
Voici quelques exemples d'utilisateurs de ce moteur :
|
||||
|
||||
### utiliser une variable
|
||||
|
||||
```
|
||||
{{ variable_name }}
|
||||
```
|
||||
|
||||
### condition
|
||||
|
||||
```
|
||||
{% if variable_name == 'oui' %}
|
||||
text
|
||||
{% endif -%}
|
||||
```
|
||||
|
||||
### boucle
|
||||
|
||||
```
|
||||
{% for var in variable_name %}
|
||||
{{ var }}
|
||||
{% endfor -%}
|
||||
```
|
||||
|
||||
### boucle avec variables meneuse et suiveuse
|
||||
|
||||
```
|
||||
{% for var in variable_leader %}
|
||||
{{ var.variable_follower }}
|
||||
{% endfor -%}
|
||||
```
|
||||
|
||||
Pour plus d'informations, voir la documentation de Jinja.
|
||||
|
||||
## Le moteur "none"
|
||||
|
||||
Ce moteur permet de copie le fichier sans y apporter la moindre modification.
|
||||
C'est utile pour les templates ne contenant aucune variable ni condition.
|
||||
39
doc/template/patch.md
vendored
39
doc/template/patch.md
vendored
|
|
@ -1,39 +0,0 @@
|
|||
# Patcher un template
|
||||
|
||||
Il peut être intéressant de réaliser un patch à un template pour corriger un problème spécifique à notre environnement, sans attendre que le mainteneur du template n'est fait la correction.
|
||||
|
||||
Par exemple le template :
|
||||
|
||||
```
|
||||
The value: %%my_value
|
||||
|
||||
The extra value: %%example.my_variable_extra
|
||||
```
|
||||
|
||||
Peut être modifié via le patch :
|
||||
|
||||
```patch
|
||||
--- tmpl/example.conf 2021-02-13 19:41:38.677491087 +0100
|
||||
+++ tmp/example.conf 2021-02-13 20:12:55.525089820 +0100
|
||||
@@ -1,3 +1,5 @@
|
||||
The value: %%my_variable
|
||||
|
||||
The extra value: %%example.my_variable_extra
|
||||
+
|
||||
+Add by a patch
|
||||
```
|
||||
|
||||
Le fichier généré ressemblera alors à cela :
|
||||
|
||||
```
|
||||
The value: my_value
|
||||
|
||||
The extra value: my_value_extra
|
||||
|
||||
Add by a patch
|
||||
```
|
||||
|
||||
Deux choses importantes à savoir sur les patchs :
|
||||
|
||||
- le nom du patch est obligatoire le nom du template source + ".patch"
|
||||
- la deuxième ligne doit toujours commencer par "+++ tmp/" (tmp étant le nom du répertoire mis dans la configuration) + le nom du template source
|
||||
|
|
@ -1,480 +1,5 @@
|
|||
# Variable
|
||||
|
||||
## Un variable
|
||||
- [Une variable](simple.md)
|
||||
- [Une variable de type choix](choice.md)
|
||||
|
||||
Une variable est forcement dans [variables](../variables.md) ou dans une [famille](../family/README.md).
|
||||
|
||||
Une variable est déjà un nom. C'est à dire qu'on pourra utiliser plus tard la variable via ce nom.
|
||||
|
||||
```xml
|
||||
<variables>
|
||||
<variable name="my_variable"/>
|
||||
<family name="my_family">
|
||||
<variable name="my_family_variable"/>
|
||||
</variable>
|
||||
</variables>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
variables:
|
||||
- variable:
|
||||
name: my_variable
|
||||
- family:
|
||||
name: my_family
|
||||
variables:
|
||||
- variable:
|
||||
name: my_family_variable
|
||||
```
|
||||
|
||||
## Description et aide sur la variable
|
||||
|
||||
En plus d'un nom, il est possible de mettre une "description" à la variable. C'est une information "utilisateur" qui nous permettra d'avoir des informations complémentaires sur le contenu de cette variable :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable" description="This is a good variable"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
variables:
|
||||
- variable:
|
||||
name: my_variable
|
||||
description: This is a good variable
|
||||
```
|
||||
|
||||
En plus de la description, il est possible de préciser une aide complémentaire :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable" help="This is a good variable"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
variables:
|
||||
- variable:
|
||||
name: my_variable
|
||||
help: This is a good variable
|
||||
```
|
||||
|
||||
Cette aide peut être utilisé à tout moment comme valeur [d'un paramètre](../param/information.md).
|
||||
|
||||
## Le type de la variable
|
||||
|
||||
Une variable a un type. Ce type permet de définir les valeurs acceptées par cette variable :
|
||||
|
||||
- string : chaine de caractère (type par défaut)
|
||||
- number : un nombre
|
||||
- float : un chiffre flottant
|
||||
- boolean : "True" ou "False", si aucune valeur n'est défini la valeur par défaut de cette variable sera "True", ces variables sont également obligatoire par défaut
|
||||
- secret (ou password mais est obsolète) : un secret (comme un mot de passe, une clef privée, ...)
|
||||
- mail : une adresse mail
|
||||
- filename : nom de fichier au sens Unix (exemple : "/etc/passwd")
|
||||
- date : une date au format "%Y-%m-%d" (exemple : "2021-01-30")
|
||||
- unix_user : nom d'utilisateur au sens Unix
|
||||
- ip : n'importe quelle adresse IPv4
|
||||
- cidr : n'importe quelle adresse IPv4 au format CIDR
|
||||
- local_ip : adresse IPv4 sur un réseau local, si l'adresse IPv4 n'est pas local, un warning sera afficher mais la valeur sera accepté tout de même
|
||||
- netmask : masque d'une adresse IPv4
|
||||
- network : adresse réseau
|
||||
- network_cidr : adresse réseau au format CIDR
|
||||
- broadcast : adresse de diffusion
|
||||
- netbios : nom netbios
|
||||
- domain : nom de domaine
|
||||
- hostname : nom d'hôte
|
||||
- web_address : adresse web (http://www.silique.fr/)
|
||||
- port : port
|
||||
- mac : adresse MAC
|
||||
- schedule : périodicité du schedule, les valeurs possibles sont "none", "daily", "weekly" ou "monthly"
|
||||
- schedulemod : type de schedule, les valeurs possibles sont "pre" ou "post"
|
||||
|
||||
Pour définir le type d'une variable :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable" type="number"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: my_variable
|
||||
type: number
|
||||
```
|
||||
|
||||
## Variable à valeur multiple
|
||||
|
||||
Par défaut une variable ne peut acceuillir qu'une seule valeur. Il peut être utile de pouvoir spécifier plusieurs valeurs à une même variable.
|
||||
|
||||
Pour définir une variable à valeur multiple :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable" multi="True"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: my_variable
|
||||
multi: true
|
||||
```
|
||||
|
||||
Par défaut, les variables multiples ne peuvent pas avoir deux fois la même valeur.
|
||||
|
||||
Si vous voulez pouvoir mettre plusieurs fois la même valeur, il faut utiliser l'attribut "unique" :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable" multi="True" unique="False"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: my_variable
|
||||
multi: true
|
||||
unique: false
|
||||
```
|
||||
|
||||
## Variable invisible
|
||||
|
||||
Il est possible de cacher une variable.
|
||||
|
||||
Cacher une variable signifie qu'elle ne sera pas visible lorsqu'on modifie la configuration du service.
|
||||
Par contre cette variable sera accessibles lorsqu'on va l'utiliser.
|
||||
|
||||
Pour cacher une variable :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable" hidden="True"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: my_variable
|
||||
hidden: true
|
||||
```
|
||||
|
||||
## Variable désactive
|
||||
|
||||
Il est possible de désactiver une variable.
|
||||
|
||||
Désactiver une variable signifie qu'elle ne sera pas visible lorsqu'on modifie la configuration du service mais également lorsqu'on va l'utiliser.
|
||||
|
||||
Pour désactiver une variable :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable" disabled="True"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: my_variable
|
||||
disabled: true
|
||||
```
|
||||
|
||||
## Variable obligatoire
|
||||
|
||||
Variable dont une valeur est requise :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable" mandatory="True"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: my_variable
|
||||
mandatory: true
|
||||
```
|
||||
|
||||
Les variables booléans sont par défaut obligatoire. Pour qu'une variable booléan ne soit pas obligatoire il faut le préciser explicitement :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable" type="boolean" mandatory="False"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: my_variable
|
||||
type: boolean
|
||||
mandatory: false
|
||||
```
|
||||
|
||||
Les variables avec une valeur par défaut (non calculée) sont également automatiquement obligatoire.
|
||||
|
||||
## Valeur par défaut d'une variable
|
||||
|
||||
Il est possible de fixer les valeurs par défaut d'une variable :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable">
|
||||
<value>value</value>
|
||||
</variable>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: my_variable
|
||||
value:
|
||||
- text: value
|
||||
```
|
||||
|
||||
Pour une variable multiple, il est possible de préciser plusieurs valeurs :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable" multi="True">
|
||||
<value>value 1</value>
|
||||
<value>value 2</value>
|
||||
</variable>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: my_variable
|
||||
multi: true
|
||||
value:
|
||||
- text: value 1
|
||||
- text: value 2
|
||||
```
|
||||
|
||||
Si la variable n'est pas pas une [variable meneuse](../family/leadership.md), la première valeur défini dans cette liste sera également la valeur par défaut proposé si on ajoute une nouvelle valeur à cette variable.
|
||||
|
||||
Une valeur par défaut peut également être [une valeur calculer](../fill/README.md).
|
||||
|
||||
## Redéfinir une variable
|
||||
|
||||
Il est possible de définir une variable dans un dictionnaire et de changer son comportement dans une second dictionnaire.
|
||||
|
||||
Attention trois attributs ne sont redéfinisable :
|
||||
|
||||
- name
|
||||
- type
|
||||
- multi
|
||||
|
||||
Créons notre variable :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: my_variable
|
||||
```
|
||||
|
||||
Et redéfinisons là :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable" redefine="True" description="New description"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: my_variable
|
||||
redefine: true
|
||||
description: New description
|
||||
```
|
||||
|
||||
## Créer une variable inexistante
|
||||
|
||||
Il est parfois utile de créer une variable si elle n'existe pas dans un autre dictionnaire :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable" exists="False"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: my_variable
|
||||
exists: false
|
||||
```
|
||||
|
||||
Si cette variable existe dans un autre dictionnaire, elle ne sera pas modifié ni recréé
|
||||
|
||||
## Redéfinir une variable si elle existe
|
||||
|
||||
Parfois on veut pouvoir redéfinir une variable mais seulement dans le cas où elle existe déjà :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable" redefine="True" exists="True" hidden="True"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: my_variable
|
||||
exists: true
|
||||
hidden: true
|
||||
```
|
||||
|
||||
## Variable à valeur automatiquement modifiée
|
||||
|
||||
Une variable avec valeur automatiquement modifiée est une variable dont la valeur sera considéré comme modifié quand la propriété global "force_store_value" de Tiramisu est mise.
|
||||
|
||||
Voici une variable a valeur automatiquement modifiée :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable" auto_save="True">
|
||||
<value>my_value</value>
|
||||
</variable>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: my_variable
|
||||
auto_save: true
|
||||
value:
|
||||
- text: my_value
|
||||
```
|
||||
|
||||
Dans ce cas la valeur est fixée à la valeur actuelle.
|
||||
Par exemple, si la valeur de cette variable est issue d'un calcul, la valeur ne sera plus recalculée.
|
||||
|
||||
Ces variables sont généralement des variables obligatoires. En effet ces variable ne sont automatiquement modifiées que si elles ont une valeurs.
|
||||
|
||||
Une [variable meneuse ou suiveuse](../family/leadership.md) ne peut pas avoir la propriété auto_save.
|
||||
|
||||
## Variable à valeur en lecture seule automatique
|
||||
|
||||
Une variable avec valeur en lecture seule automatique est une variable dont la valeur ne sera plus modifiable par l'utilisateur quand la [variable "server_deployed" passe à "True"](../dev/config.md).
|
||||
|
||||
Voici un variable à valeur en lecture seule automatique :
|
||||
|
||||
```xml
|
||||
<variable name="server_deployed" type="boolean">
|
||||
<value>False</value>
|
||||
</variable>
|
||||
<variable name="my_variable" auto_freeze="True"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: server_deployed
|
||||
type: boolean
|
||||
value:
|
||||
- text: 'False
|
||||
- variable:
|
||||
name: my_variable
|
||||
auto_freeze: true
|
||||
```
|
||||
|
||||
Dans ce cas la valeur est fixée à la valeur actuelle et elle ne sera plus modifiable par l'utilisateur.
|
||||
Par exemple, si la valeur de cette variable est issue d'un calcul, la valeur ne sera plus recalculée.
|
||||
|
||||
Ces variables sont généralement des variables obligatoires. En effet ces variable ne sont en lecteur seul que si elles ont une valeurs.
|
||||
|
||||
Une [variable meneuse ou suiveuse](../family/leadership.md) ne peut pas avoir la propriété auto_freeze.
|
||||
|
||||
## Information "test"
|
||||
|
||||
L'attribut "test" est un attribut spécial qui permet aux concepteurs d'un dictionnaire d'influancer le robot de test en précisant de valeurs utile à tester.
|
||||
|
||||
Concrêtement, le contenu de cet attribut est enregister dans une "information" de l'option Tiramisu correspondante.
|
||||
|
||||
Exemple :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable" test="yes"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: my_variable
|
||||
test: yes
|
||||
```
|
||||
|
||||
Il est possible de préciser plusieurs valeurs avec le séparateur "|" :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable" test="yes|no"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: my_variable
|
||||
test: yes|no
|
||||
```
|
||||
|
||||
Cette valeur peut être utilisé à tout moment comme valeur [d'un paramètre](../param/information.md).
|
||||
|
||||
## Mode de la variable
|
||||
|
||||
Le [mode](../mode.md) par défaut d'une variable correspond au [mode](../mode.md) de la [famille](../family/README.md).
|
||||
|
||||
Cas particuliers :
|
||||
|
||||
- une variable à valeur automatiquement modifiée ou une variable en lecture seule automatique est par défaut en mode "basic".
|
||||
- si la variable n'est pas dans une famille, la variable aura le mode "normal" par défaut.
|
||||
- une variable obligatoire sans valeur par défaut (calculer ou non) aura le mode "basic".
|
||||
|
||||
Pour définir le [mode](../mode.md) :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable" mode="expert"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: my_variable
|
||||
mode: expert
|
||||
```
|
||||
|
||||
## Les variables qui fournissent des valeurs
|
||||
|
||||
Il peut être intéressant de retrouver facilement des variables sans connaitre le chemin complet mais en utilisant le contenu du paramètre "provider".
|
||||
C'est particulièrement utile si un service peut être fournit par plusieurs services. Les variables n'auront donc pas le même nom. Utiliser ce paramètre, permet donc de retrouver facilement la variable.
|
||||
|
||||
Pour déclarer :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable" provider="my_function"/>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: my_variable
|
||||
provider: my_variable
|
||||
```
|
||||
|
||||
Dans le code de l'application, on pourra retrouver le chemin de la variable en faisant :
|
||||
|
||||
```python
|
||||
print(await config.information.get('provider:my_function'))
|
||||
```
|
||||
|
||||
Pour les variables inclusent dans une famille dynamique, le chemin de la variable sera un template comme ceci "rougail.family_{suffix}.my_variable_{suffix}". Il vous suffit de remplacer "{suffix}" par le suffix voulu de la famille dynamique.
|
||||
|
|
|
|||
|
|
@ -4,24 +4,15 @@
|
|||
|
||||
Il est possible d'imposer une liste de valeur pour une variable particulière :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable" type="choice">
|
||||
<choice>val1</choice>
|
||||
<choice>val2</choice>
|
||||
<choice>val3</choice>
|
||||
</variable>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: my_variable
|
||||
type: choice
|
||||
choice:
|
||||
- text: val1
|
||||
- text: val2
|
||||
- text: val3
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
type: choice
|
||||
choices:
|
||||
- val1
|
||||
- val2
|
||||
- val3
|
||||
```
|
||||
|
||||
Dans ce cas, seules les valeurs proposées sont possibles pour cette variable.
|
||||
|
|
@ -29,158 +20,113 @@ Cette variable n'est pas obligatoire dont il est possible de mettre la valeur "N
|
|||
|
||||
Si la variable est obligatoire ou si une valeur est précisée (la variable passe obligatoire) alors la valeur "None" n'est plus autorisé :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable" type="choice">
|
||||
<choice>val1</choice>
|
||||
<choice>val2</choice>
|
||||
<choice>val3</choice>
|
||||
<value>val1</value>
|
||||
</variable>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: my_variable
|
||||
type: choice
|
||||
choice:
|
||||
- text: val1
|
||||
- text: val2
|
||||
- text: val3
|
||||
value:
|
||||
- text: val1
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
type: choice
|
||||
choices:
|
||||
- val1
|
||||
- val2
|
||||
- val3
|
||||
default: val1
|
||||
```
|
||||
|
||||
## Un variable à choix typée
|
||||
|
||||
Par défaut les choix sont de type "string". Il est possible de préciser des nombres, des booléens ou la valeur None :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable" type="choice">
|
||||
<choice>val1</choice>
|
||||
<choice type="string">val2</choice>
|
||||
<choice type="number">3</choice>
|
||||
<choice type="boolean">True</choice>
|
||||
<choice type="nil"/>
|
||||
</variable>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
Les choix sont typés :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: my_variable
|
||||
type: choice
|
||||
choice:
|
||||
- text: val1
|
||||
- type: string
|
||||
text: val2
|
||||
- type: number
|
||||
text: 3
|
||||
- type: boolean
|
||||
text: true
|
||||
- type: 'nil'
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
type: choice
|
||||
choices:
|
||||
- val1
|
||||
- 3
|
||||
- true
|
||||
default: val1
|
||||
```
|
||||
|
||||
Comme vu précédement ajouter la valeur None n'est pas utile parce qu'elle est automatiquement ajouté si la variable n'est pas obligatoire.
|
||||
|
||||
## Ajouter une option à une variable à choix existante
|
||||
|
||||
Pour ajouter un choix à une variable à choix existante, rien de plus simple, juste redéfinir la variable en ajoutant le choix voulu :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable" redefine="True">
|
||||
<choice>val4</choice>
|
||||
</variable>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: my_variable
|
||||
redefine: true
|
||||
choice:
|
||||
- text: val4
|
||||
```
|
||||
dans ce cas, le chiffre 3 est autorisé mais pas la chaine de caractère "3".
|
||||
|
||||
## Redéfinir une option à choix
|
||||
|
||||
Si on veut supprimer un choix ou redéfinir complètement la liste, il faut redéfinir cette variable et ajouter l'attribut "remove_choice" à "True" :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable" redefine="True" remove_choice="True">
|
||||
<choice>val1</choice>
|
||||
<choice>val2</choice>
|
||||
</variable>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: my_variable
|
||||
redefine: true
|
||||
remove_choice: true
|
||||
choice:
|
||||
- text: val1
|
||||
- text: val2
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
redefine: true
|
||||
choices:
|
||||
- val1
|
||||
- val2
|
||||
```
|
||||
|
||||
Dans ce cas toutes les anciens choix ne seront plus possible. Seuls les nouveaux le seront.
|
||||
|
||||
## Un variable à choix provenant d'une variable
|
||||
## Un variable à choix provenant de variable
|
||||
|
||||
Une variable à valeur multiple peut servir de source des choix :
|
||||
|
||||
```xml
|
||||
<variable name="my_variable" type="choice">
|
||||
<choice type="variable">other_variable</choice>
|
||||
</variable>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
Les choix d'une variable peuvent provenir d'une autre variable multiple :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: my_variable
|
||||
type: choice
|
||||
choice:
|
||||
---
|
||||
version: '1.0'
|
||||
source_variable:
|
||||
multi: true
|
||||
default:
|
||||
- val1
|
||||
- val2
|
||||
my_variable:
|
||||
type: choice
|
||||
choices:
|
||||
type: variable
|
||||
variable: rougail.source_variable
|
||||
```
|
||||
|
||||
Ou de plusieurs autres variables :
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
source_variable_1:
|
||||
default: val1
|
||||
source_variable_2:
|
||||
default: val2
|
||||
my_variable:
|
||||
type: choice
|
||||
choices:
|
||||
- type: variable
|
||||
text: other_variable
|
||||
variable: rougail.source_variable_1
|
||||
- type: variable
|
||||
variable: rougail.source_variable_2
|
||||
```
|
||||
|
||||
Dans ce cas, toutes les valeurs de la variable seront des choix utilisables par l'utilisateur.
|
||||
Seul un choice de type "variable" est possible par variable.
|
||||
Dans ce cas, toutes les valeurs de la variable ou des variables seront des choix utilisables par l'utilisateur.
|
||||
|
||||
## Un variable à choix provenant d'une fonction
|
||||
## Un variable à choix provenant d'une fonction jinja
|
||||
|
||||
```xml
|
||||
<variable name="my_variable" type="choice">
|
||||
<choice type="function" name="range">
|
||||
<param type="number">0</param>
|
||||
<param type="number">10</param>
|
||||
</choice>
|
||||
<value type="number">9</value>
|
||||
</variable>
|
||||
Faisons d'abord une fonction `trange` dans le fichier functions.py :
|
||||
|
||||
```python
|
||||
def trange(min, max):
|
||||
return range(min, ma
|
||||
```
|
||||
|
||||
En YAML :
|
||||
On va récupérer ici les valeurs de 0 à 9 :
|
||||
|
||||
```yml
|
||||
- variable:
|
||||
name: my_variable
|
||||
type: choice
|
||||
choice:
|
||||
- type: function
|
||||
name: range
|
||||
param:
|
||||
- type: number
|
||||
text: 0
|
||||
- type: number
|
||||
text: 10
|
||||
value:
|
||||
- type: number
|
||||
text: 9
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
type: choice
|
||||
default: 9
|
||||
choices:
|
||||
type: jinja
|
||||
jinja: |+
|
||||
{% for item in trange(0, 10) %}
|
||||
{{ item }}
|
||||
{%- endfor %}
|
||||
return_type: number
|
||||
```
|
||||
|
|
|
|||
342
doc/variable/simple.md
Normal file
342
doc/variable/simple.md
Normal file
|
|
@ -0,0 +1,342 @@
|
|||
# Variable
|
||||
|
||||
Une variable est un conteneur qui contiendra une ou plusieurs valeurs.
|
||||
|
||||
## Un variable
|
||||
|
||||
Une variable est déjà un nom.
|
||||
C'est à dire qu'on pourra utiliser plus tard la variable via ce nom.
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
```
|
||||
|
||||
Il est recommander de n'utiliser que des lettres, chiffres et '\_' dans le nom des variables. Le nom ne pas commencé par le caractère "\_".
|
||||
|
||||
## Le type de la variable
|
||||
|
||||
Une variable a un type. Ce type permet de définir les valeurs acceptées par cette variable :
|
||||
|
||||
- string : chaine de caractère (type par défaut)
|
||||
- number : un nombre
|
||||
- float : un chiffre flottant
|
||||
- boolean : "True" ou "False", si aucune valeur n'est défini la valeur par défaut de cette variable sera "True", ces variables sont également obligatoire par défaut
|
||||
- secret : un secret (comme un mot de passe, une clef privée, ...)
|
||||
- mail : une adresse mail
|
||||
- filename : nom de fichier au sens Unix (exemple : "/etc/passwd")
|
||||
- date : une date au format "%Y-%m-%d" (exemple : "2021-01-30")
|
||||
- unix_user : nom d'utilisateur au sens Unix
|
||||
- ip : n'importe quelle adresse IPv4
|
||||
- cidr : n'importe quelle adresse IPv4 au format CIDR
|
||||
- local_ip : adresse IPv4 sur un réseau local, si l'adresse IPv4 n'est pas local, un warning sera afficher mais la valeur sera accepté tout de même
|
||||
- netmask : masque d'une adresse IPv4
|
||||
- network : adresse réseau
|
||||
- network_cidr : adresse réseau au format CIDR
|
||||
- broadcast : adresse de diffusion
|
||||
- netbios : nom netbios
|
||||
- domainname : nom de domaine
|
||||
- hostname : nom d'hôte
|
||||
- web_address : adresse web (http://www.silique.fr/)
|
||||
- port : port
|
||||
- mac : adresse MAC
|
||||
- unix_permissions : droit d'accès au fichier, répertoire, ...
|
||||
- [choix](choice.md)
|
||||
|
||||
Pour définir le type d'une variable :
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
type: number
|
||||
```
|
||||
|
||||
Dans certain ce cas, il n'est pas possible de distinger une variable d'une famille. Le type est donc obligatoire.
|
||||
Il faudra dans ce cas mettre le type par défaut :
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
type: string
|
||||
```
|
||||
|
||||
## Description et aide sur la variable
|
||||
|
||||
En plus d'un nom et du type, il est possible de mettre une "description" à la variable. C'est une information "utilisateur" qui nous permettra d'avoir des informations complémentaires sur le contenu de cette variable :
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
type: string
|
||||
description: This is a good variable
|
||||
```
|
||||
|
||||
En plus de la description, il est possible de préciser une aide complémentaire :
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
type: string
|
||||
help: This is a good variable
|
||||
```
|
||||
|
||||
Cette aide peut être utilisé à tout moment comme valeur [d'un paramètre](../param/information.md).
|
||||
|
||||
## Variable à valeur multiple
|
||||
|
||||
Par défaut une variable ne peut acceuillir qu'une seule valeur. Il peut être utile de pouvoir spécifier plusieurs valeurs à une même variable.
|
||||
|
||||
Pour définir une variable à valeur multiple :
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
multi: true
|
||||
```
|
||||
|
||||
Par défaut, les variables multiples ne peuvent pas avoir deux fois la même valeur.
|
||||
Si vous voulez pouvoir mettre plusieurs fois la même valeur, il faut utiliser l'attribut `unique` :
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
multi: true
|
||||
unique: false
|
||||
```
|
||||
|
||||
## Les propriétés
|
||||
|
||||
### Variable invisible
|
||||
|
||||
Il est possible de cacher une variable.
|
||||
|
||||
Cacher une variable signifie qu'elle ne sera pas visible lorsqu'on modifie la configuration.
|
||||
Par contre cette variable sera accessibles lorsqu'on va l'utiliser.
|
||||
|
||||
Pour cacher une variable :
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
type: string
|
||||
hidden: true
|
||||
```
|
||||
|
||||
Lorsqu'on rend invisible une variable l'utilisateur ne pourra pas modifier sa valeur, il s'il a déjà réussi à la modifier, cette valeur ne sera pas prise en compte.
|
||||
|
||||
[La valeur de cet attribut peut être fixé par un calcul](../condition/README.md).
|
||||
|
||||
### Variable désactive
|
||||
|
||||
Il est possible de désactiver une variable.
|
||||
|
||||
Désactiver une variable signifie qu'elle ne sera pas visible lorsqu'on modifie la configuration mais également lorsqu'on va l'utiliser.
|
||||
|
||||
Pour désactiver une variable :
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
type: string
|
||||
disabled: true
|
||||
```
|
||||
|
||||
[La valeur de cet attribut peut être fixé par un calcul](../condition/README.md).
|
||||
|
||||
### Variable obligatoire
|
||||
|
||||
Variable dont une valeur est requise :
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
type: string
|
||||
mandatory: true
|
||||
```
|
||||
|
||||
Les variables booléans sont par défaut obligatoire. Pour qu'une variable booléan ne soit pas obligatoire il faut le préciser explicitement :
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
type: boolean
|
||||
mandatory: false
|
||||
```
|
||||
|
||||
Les variables avec une valeur par défaut (non calculée) sont également automatiquement obligatoire.
|
||||
|
||||
[La valeur de cet attribut peut être fixé par un calcul](../condition/README.md).
|
||||
|
||||
## Valeur par défaut d'une variable
|
||||
|
||||
Il est possible de fixer les valeurs par défaut d'une variable :
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
default: value
|
||||
```
|
||||
|
||||
Pour une variable multiple, la valeur par défaut doit être une liste et il est possible de préciser plusieurs valeurs :
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
multi: true
|
||||
default:
|
||||
- value
|
||||
my_variable:
|
||||
multi: true
|
||||
default:
|
||||
- value1
|
||||
- value2
|
||||
```
|
||||
|
||||
Par défaut, les variables multiples ne peuvent pas avoir deux fois la même valeur.
|
||||
Si vous voulez pouvoir mettre plusieurs fois la même valeur, il faut utiliser l'attribut "unique" :
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
multi: true
|
||||
unique: false
|
||||
default:
|
||||
- value1
|
||||
- value2
|
||||
- value2
|
||||
```
|
||||
|
||||
Si la variable n'est pas pas une [variable meneuse](../family/leadership.md), la première valeur défini dans cette liste sera également la valeur par défaut proposé si on ajoute une nouvelle valeur à cette variable.
|
||||
|
||||
Une valeur par défaut peut également être [une valeur calculer](../fill/README.md).
|
||||
|
||||
## Redéfinir une variable
|
||||
|
||||
Il est possible de définir une variable dans un dictionnaire et de changer son comportement dans une second dictionnaire.
|
||||
|
||||
Créons notre variable :
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
type: string
|
||||
```
|
||||
|
||||
Et redéfinisons là :
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
redefine: true
|
||||
description: New description
|
||||
```
|
||||
|
||||
## Créer une variable inexistante
|
||||
|
||||
Il est parfois utile de créer une variable si elle n'existe pas dans un autre dictionnaire :
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
exists: false
|
||||
```
|
||||
|
||||
Si cette variable existe dans un autre dictionnaire, elle ne sera pas modifié ni recréé.
|
||||
|
||||
## Redéfinir une variable si elle existe
|
||||
|
||||
Parfois on veut pouvoir redéfinir une variable mais seulement dans le cas où elle existe déjà :
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
exists: true
|
||||
hidden: true
|
||||
```
|
||||
|
||||
Dans ce cas la variable ne sera pas créé mais uniquement cachée si elle existe déjà.
|
||||
|
||||
## Variable à valeur automatiquement modifiée
|
||||
|
||||
Une variable avec valeur automatiquement modifiée est une variable dont la valeur sera considéré comme modifié par l'utilisateur (ce n'est plus une valeur par défaut).
|
||||
|
||||
Voici une variable a valeur automatiquement modifiée :
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
auto_save: true
|
||||
default: my_value
|
||||
```
|
||||
|
||||
Dans ce cas la valeur est fixée à la valeur actuelle.
|
||||
Par exemple, si la valeur de cette variable est issue d'un calcul, la valeur ne sera plus recalculée.
|
||||
|
||||
Ces variables sont généralement des variables obligatoires. En effet ces variable ne sont automatiquement modifiées que si elles ont une valeurs.
|
||||
|
||||
Une [variable meneuse ou suiveuse](../family/leadership.md) ne peut pas avoir la propriété `auto_save`.
|
||||
|
||||
## Information "test"
|
||||
|
||||
L'attribut "test" est un attribut spécial qui permet aux concepteurs d'un dictionnaire d'influancer le robot de test en précisant de valeurs utile à tester.
|
||||
|
||||
Concrêtement, le contenu de cet attribut est enregister dans une "information" de l'option Tiramisu correspondante.
|
||||
|
||||
Exemple :
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
test: 'yes'
|
||||
```
|
||||
|
||||
Il est possible de préciser plusieurs valeurs avec le séparateur "|" :
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
test: 'yes|no'
|
||||
```
|
||||
|
||||
Cette valeur peut être utilisé à tout moment comme valeur [d'un paramètre](../param/information.md).
|
||||
|
||||
## Mode de la variable
|
||||
|
||||
Le [mode](../mode.md) par défaut d'une variable correspond au [mode](../mode.md) de la [famille](../family/README.md).
|
||||
|
||||
Cas particuliers :
|
||||
|
||||
- une variable à valeur automatiquement modifiée ou une variable en lecture seule automatique est par défaut en mode "basic".
|
||||
- si la variable n'est pas dans une famille, la variable aura le mode "normal" par défaut.
|
||||
- une variable obligatoire sans valeur par défaut (calculer ou non) aura le mode "basic".
|
||||
|
||||
Pour définir le [mode](../mode.md) :
|
||||
|
||||
```yml
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
type: string
|
||||
mode: expert
|
||||
```
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
# Le conteneur des variables
|
||||
|
||||
La balise "variables" est le conteneur de l'ensemble des [familles](family/README.md) et des [variables](variable/README.md).
|
||||
|
||||
Il est placé à la racine du dictionnaire :
|
||||
|
||||
```xml
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<rougail>
|
||||
<variables/>
|
||||
</rougail>
|
||||
```
|
||||
|
||||
En YAML :
|
||||
|
||||
```yml
|
||||
version: '0.10'
|
||||
variables: none
|
||||
```
|
||||
|
|
@ -47,10 +47,11 @@ class Rougail:
|
|||
|
||||
def get_config(self):
|
||||
if not self.config:
|
||||
tiram_obj = self.converted.save(None)
|
||||
tiram_obj = self.converted.save(self.rougailconfig['tiramisu_cache'])
|
||||
optiondescription = {}
|
||||
exec(tiram_obj, None, optiondescription)
|
||||
self.config = Config(optiondescription['option_0'])
|
||||
self.config.property.read_write()
|
||||
return self.config
|
||||
|
||||
def template(self,
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ def get_annotators(annotators, module_name):
|
|||
annotators[module_name] = []
|
||||
for pathobj in importlib.resources.files(module_name).iterdir():
|
||||
path = str(pathobj)
|
||||
if path.endswith('__') or path.endswith('__.py'):
|
||||
if not path.endswith('.py') or path.endswith('__.py'):
|
||||
continue
|
||||
module = load_modules(path)
|
||||
if 'Annotator' not in dir(module):
|
||||
|
|
@ -84,17 +84,20 @@ class SpaceAnnotator: # pylint: disable=R0903
|
|||
for extra_annotator in objectspace.rougailconfig['extra_annotators']:
|
||||
annotators.extend(ANNOTATORS[extra_annotator])
|
||||
annotators = sorted(annotators, key=get_level)
|
||||
functions = []
|
||||
functions = {}
|
||||
functions_files = objectspace.rougailconfig['functions_file']
|
||||
if not isinstance(functions_files, list):
|
||||
functions_files = [functions_files]
|
||||
for functions_file in functions_files:
|
||||
if isfile(functions_file):
|
||||
functions.extend(dir(load_modules(functions_file)))
|
||||
loaded_modules = load_modules(functions_file)
|
||||
for function in dir(loaded_modules):
|
||||
if function.startswith('_'):
|
||||
continue
|
||||
functions[function] = getattr(loaded_modules, function)
|
||||
objectspace.functions = functions
|
||||
for annotator in annotators:
|
||||
annotator(objectspace,
|
||||
functions,
|
||||
)
|
||||
annotator(objectspace)
|
||||
|
||||
|
||||
__all__ = ('SpaceAnnotator', 'CONVERT_OPTION')
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ from copy import copy
|
|||
|
||||
from rougail.annotator.target import TargetAnnotator
|
||||
from rougail.annotator.param import ParamAnnotator
|
||||
from rougail.annotator.fill import get_jinja_variable_to_param
|
||||
#from rougail.annotator.fill import get_jinja_variable_to_param
|
||||
|
||||
from rougail.i18n import _
|
||||
from rougail.error import DictConsistencyError, display_xmlfiles
|
||||
|
|
@ -45,9 +45,9 @@ class Annotator(TargetAnnotator, ParamAnnotator):
|
|||
level = 40
|
||||
def __init__(self,
|
||||
objectspace,
|
||||
functions,
|
||||
*args,
|
||||
):
|
||||
return
|
||||
self.objectspace = objectspace
|
||||
self.only_variable = True
|
||||
self.target_is_uniq = False
|
||||
|
|
|
|||
|
|
@ -52,24 +52,22 @@ class Annotator(TargetAnnotator, ParamAnnotator, Walk):
|
|||
*args,
|
||||
):
|
||||
self.objectspace = objectspace
|
||||
self.target_is_uniq = False
|
||||
self.only_variable = False
|
||||
self.allow_function = False
|
||||
self.force_service_value = {}
|
||||
if hasattr(objectspace.space, 'variables'):
|
||||
self.convert_auto_freeze()
|
||||
for path_prefix, constraints in self.get_constraints():
|
||||
if not hasattr(constraints, 'condition'):
|
||||
continue
|
||||
self.convert_target(constraints.condition, path_prefix)
|
||||
self.check_condition_optional(constraints, path_prefix)
|
||||
self.convert_condition_source(constraints, path_prefix)
|
||||
self.convert_param(constraints.condition, path_prefix)
|
||||
self.check_source_target(constraints)
|
||||
self.convert_xxxlist(constraints, path_prefix)
|
||||
self.check_choice_option_condition(constraints, path_prefix)
|
||||
self.remove_condition_with_empty_target(constraints)
|
||||
self.convert_condition(constraints, path_prefix)
|
||||
# self.target_is_uniq = False
|
||||
# self.only_variable = False
|
||||
# self.allow_function = False
|
||||
# self.force_service_value = {}
|
||||
#for path_prefix, constraints in self.get_constraints():
|
||||
# if not hasattr(constraints, 'condition'):
|
||||
# continue
|
||||
# self.convert_target(constraints.condition, path_prefix)
|
||||
# self.check_condition_optional(constraints, path_prefix)
|
||||
# self.convert_condition_source(constraints, path_prefix)
|
||||
# self.convert_param(constraints.condition, path_prefix)
|
||||
# self.check_source_target(constraints)
|
||||
# self.convert_xxxlist(constraints, path_prefix)
|
||||
# self.check_choice_option_condition(constraints, path_prefix)
|
||||
# self.remove_condition_with_empty_target(constraints)
|
||||
# self.convert_condition(constraints, path_prefix)
|
||||
|
||||
def valid_type_validation(self,
|
||||
obj,
|
||||
|
|
@ -78,47 +76,6 @@ class Annotator(TargetAnnotator, ParamAnnotator, Walk):
|
|||
return None
|
||||
return obj.source.type
|
||||
|
||||
def convert_auto_freeze(self):
|
||||
"""convert auto_freeze
|
||||
only if auto_freeze_variable is True this variable is frozen
|
||||
"""
|
||||
for variable in self.get_variables():
|
||||
if not variable.auto_freeze and not variable.auto_save:
|
||||
continue
|
||||
#if variable.namespace != self.objectspace.rougailconfig['variable_namespace']:
|
||||
# msg = _(f'auto_freeze is not allowed in extra "{variable.namespace}"')
|
||||
# raise DictConsistencyError(msg, 49, variable.xmlfiles)
|
||||
variable.force_store_value = True
|
||||
if variable.auto_save:
|
||||
continue
|
||||
auto_freeze_variable = self.objectspace.rougailconfig['auto_freeze_variable']
|
||||
if not self.objectspace.paths.path_is_defined(auto_freeze_variable,
|
||||
self.objectspace.rougailconfig['variable_namespace'],
|
||||
variable.path_prefix,
|
||||
):
|
||||
msg = _(f'the variable "{variable.name}" is auto_freeze but there is no variable "{auto_freeze_variable}"')
|
||||
raise DictConsistencyError(msg, 81, variable.xmlfiles)
|
||||
new_condition = self.objectspace.condition(variable.xmlfiles)
|
||||
new_condition.name = 'auto_frozen_if_in'
|
||||
new_condition.namespace = variable.namespace
|
||||
new_condition.source = auto_freeze_variable
|
||||
new_param = self.objectspace.param(variable.xmlfiles)
|
||||
new_param.text = True
|
||||
new_condition.param = [new_param]
|
||||
new_target = self.objectspace.target(variable.xmlfiles)
|
||||
new_target.type = 'variable'
|
||||
path = variable.path
|
||||
if variable.path_prefix:
|
||||
path = path.split('.', 1)[-1]
|
||||
new_target.name = path
|
||||
new_condition.target = [new_target]
|
||||
path_prefix, constraints = next(self.get_constraints(create=True,
|
||||
path_prefix=variable.path_prefix,
|
||||
))
|
||||
if not hasattr(constraints, 'condition'):
|
||||
constraints.condition = []
|
||||
constraints.condition.append(new_condition)
|
||||
|
||||
def check_source_target(self, constraints):
|
||||
"""verify that source != target in condition
|
||||
"""
|
||||
|
|
@ -404,7 +361,7 @@ class Annotator(TargetAnnotator, ParamAnnotator, Walk):
|
|||
main_action,
|
||||
)
|
||||
if isinstance(leader_or_variable, self.objectspace.variable) and \
|
||||
(leader_or_variable.auto_save or leader_or_variable.auto_freeze) and \
|
||||
leader_or_variable.auto_save and \
|
||||
'force_default_on_freeze' in actions:
|
||||
continue
|
||||
for action in actions[1:]:
|
||||
|
|
|
|||
|
|
@ -54,8 +54,9 @@ class Annotator(Walk):
|
|||
objectspace,
|
||||
*args,
|
||||
):
|
||||
self.mode_auto = []
|
||||
self.objectspace = objectspace
|
||||
if not hasattr(self.objectspace.space, 'variables'):
|
||||
if not self.objectspace.paths:
|
||||
return
|
||||
self.modes = {name: Mode(idx) for idx, name in enumerate(self.objectspace.rougailconfig['modes_level'])}
|
||||
self.remove_empty_families()
|
||||
|
|
@ -67,34 +68,34 @@ class Annotator(Walk):
|
|||
def remove_empty_families(self) -> None:
|
||||
"""Remove all families without any variable
|
||||
"""
|
||||
removed_families = {}
|
||||
for family, parent in self.get_families(with_parent=True):
|
||||
if isinstance(family, self.objectspace.family) and not self._has_variable(family):
|
||||
removed_families.setdefault(parent, []).append(family)
|
||||
for parent, families in removed_families.items():
|
||||
for family in families:
|
||||
del parent.variable[family.name]
|
||||
removed_families = []
|
||||
for family in self.get_families():
|
||||
if isinstance(family, self.objectspace.family) and not self._has_variable(family.path):
|
||||
if '.' in family.path:
|
||||
removed_families.append(family.path)
|
||||
removed_families.reverse()
|
||||
for family in removed_families:
|
||||
self.objectspace.del_family(family)
|
||||
|
||||
def _has_variable(self,
|
||||
family: 'self.objectspace.family',
|
||||
family: str,
|
||||
) -> bool:
|
||||
if hasattr(family, 'variable'):
|
||||
for variable in family.variable.values():
|
||||
if isinstance(variable, self.objectspace.family):
|
||||
if self._has_variable(variable):
|
||||
return True
|
||||
else:
|
||||
for variable in self.objectspace.parents[family]:
|
||||
if variable in self.objectspace.families:
|
||||
if self._has_variable(variable):
|
||||
return True
|
||||
else:
|
||||
return True
|
||||
return False
|
||||
|
||||
def family_names(self) -> None:
|
||||
"""Set doc, path, ... to family
|
||||
"""
|
||||
for family in self.get_families():
|
||||
if not hasattr(family, 'description'):
|
||||
if not family.description:
|
||||
family.description = family.name
|
||||
family.doc = family.description
|
||||
del family.description
|
||||
# family.doc = family.description
|
||||
# del family.description
|
||||
|
||||
def change_modes(self):
|
||||
"""change the mode of variables
|
||||
|
|
@ -130,17 +131,21 @@ class Annotator(Walk):
|
|||
def _set_default_mode(self,
|
||||
family: 'self.objectspace.family',
|
||||
) -> None:
|
||||
if not hasattr(family, 'variable'):
|
||||
children = self.objectspace.parents[family.path]
|
||||
if not children:
|
||||
return
|
||||
if self._has_mode(family):
|
||||
family_mode = family.mode
|
||||
else:
|
||||
family_mode = None
|
||||
leader = None
|
||||
for variable in family.variable.values():
|
||||
if leader is None and hasattr(family, 'leadership') and family.leadership:
|
||||
for variable_path in children:
|
||||
variable = self.objectspace.paths[variable_path]
|
||||
if variable.type == 'symlink':
|
||||
continue
|
||||
if leader is None and family.type == 'leadership':
|
||||
leader = variable
|
||||
if isinstance(variable, self.objectspace.family):
|
||||
if variable_path in self.objectspace.families:
|
||||
# set default mode a subfamily
|
||||
if family_mode and not self._has_mode(variable):
|
||||
self._set_auto_mode(variable, family_mode)
|
||||
|
|
@ -154,32 +159,33 @@ class Annotator(Walk):
|
|||
# here because follower can change leader mode
|
||||
self._set_auto_mode(family, leader.mode)
|
||||
|
||||
@staticmethod
|
||||
def _has_mode(obj) -> bool:
|
||||
return 'mode' in vars(obj) and not hasattr(obj, 'mode_auto')
|
||||
def _has_mode(self, obj) -> bool:
|
||||
return obj.mode and not obj.path in self.mode_auto
|
||||
|
||||
def _set_default_mode_variable(self,
|
||||
variable: 'self.objectspace.variable',
|
||||
family_mode: str,
|
||||
) -> None:
|
||||
# auto_save or auto_freeze variable is set to 'basic' mode
|
||||
# auto_save variable is set to 'basic' mode
|
||||
# if its mode is not defined by the user
|
||||
if not self._has_mode(variable) and \
|
||||
(variable.auto_save is True or variable.auto_freeze is True):
|
||||
variable.auto_save is True:
|
||||
variable.mode = self.objectspace.rougailconfig['modes_level'][0]
|
||||
# mandatory variable without value is a basic variable
|
||||
elif not self._has_mode(variable) and \
|
||||
variable.mandatory is True and \
|
||||
not hasattr(variable, 'default') and \
|
||||
not hasattr(variable, 'default_multi'):
|
||||
variable.default is None and \
|
||||
variable.path not in self.objectspace.default_multi:
|
||||
variable.mode = self.objectspace.rougailconfig['modes_level'][0]
|
||||
elif family_mode and not self._has_mode(variable):
|
||||
self._set_auto_mode(variable, family_mode)
|
||||
|
||||
@staticmethod
|
||||
def _set_auto_mode(obj, mode: str) -> None:
|
||||
def _set_auto_mode(self,
|
||||
obj,
|
||||
mode: str,
|
||||
) -> None:
|
||||
obj.mode = mode
|
||||
obj.mode_auto = True
|
||||
self.mode_auto.append(obj.path)
|
||||
|
||||
def _set_default_mode_leader(self,
|
||||
leader: 'self.objectspace.variable',
|
||||
|
|
@ -188,12 +194,9 @@ class Annotator(Walk):
|
|||
if follower.auto_save is True:
|
||||
msg = _(f'leader/followers "{follower.name}" could not be auto_save')
|
||||
raise DictConsistencyError(msg, 29, follower.xmlfiles)
|
||||
if follower.auto_freeze is True:
|
||||
msg = f'leader/followers "{follower.name}" could not be auto_freeze'
|
||||
raise DictConsistencyError(_(msg), 30, follower.xmlfiles)
|
||||
if leader == follower:
|
||||
# it's a leader
|
||||
if not hasattr(leader, 'mode'):
|
||||
if not leader.mode:
|
||||
self._set_auto_mode(leader, self.objectspace.rougailconfig['default_variable_mode'])
|
||||
return
|
||||
if self._has_mode(follower):
|
||||
|
|
@ -215,44 +218,42 @@ class Annotator(Walk):
|
|||
def _change_family_mode(self,
|
||||
family: 'self.objectspace.family',
|
||||
) -> None:
|
||||
if hasattr(family, 'mode'):
|
||||
if family.mode:
|
||||
family_mode = family.mode
|
||||
else:
|
||||
family_mode = self.objectspace.rougailconfig['default_family_mode']
|
||||
min_variable_mode = self.objectspace.rougailconfig['modes_level'][-1]
|
||||
# change variable mode, but not if variables are not in a family
|
||||
is_leadership = hasattr(family, 'leadership') and family.leadership
|
||||
if hasattr(family, 'variable'):
|
||||
for idx, variable in enumerate(family.variable.values()):
|
||||
if isinstance(variable, self.objectspace.family):
|
||||
if not hasattr(variable, 'mode'):
|
||||
is_leadership = family.type == 'leadership'
|
||||
if family.path in self.objectspace.parents:
|
||||
for idx, variable_path in enumerate(self.objectspace.parents[family.path]):
|
||||
variable = self.objectspace.paths[variable_path]
|
||||
if variable.type == 'symlink':
|
||||
continue
|
||||
if variable_path in self.objectspace.families:
|
||||
if not variable.mode:
|
||||
variable.mode = self.objectspace.rougailconfig['default_family_mode']
|
||||
#elif idx == 0 and is_leadership:
|
||||
# variable.mode = None
|
||||
# if variable.path == 'general.piwigo.users.piwigo_users':
|
||||
# print(variable.path)
|
||||
# continue
|
||||
else:
|
||||
self._change_variable_mode(variable, family_mode, is_leadership)
|
||||
if self.modes[min_variable_mode] > self.modes[variable.mode]:
|
||||
min_variable_mode = variable.mode
|
||||
if not isinstance(family, (self.objectspace.family, self.objectspace.variables)):
|
||||
# it's Variable, Service, ...
|
||||
return
|
||||
if not hasattr(family, 'mode'):
|
||||
#FIXME if not isinstance(family, (self.objectspace.family, self.objectspace.variables)):
|
||||
# # it's Variable, Service, ...
|
||||
# return
|
||||
if not family.mode:
|
||||
# set the lower variable mode to family
|
||||
self._set_auto_mode(family, min_variable_mode)
|
||||
if not is_leadership and family.mode != min_variable_mode:
|
||||
msg = _(f'the family "{family.name}" is in "{family.mode}" mode but variables and '
|
||||
f'families inside have the higher modes "{min_variable_mode}"')
|
||||
raise DictConsistencyError(msg, 62, family.xmlfiles)
|
||||
#FIXME if not is_leadership and family.mode != min_variable_mode:
|
||||
#FIXME msg = _(f'the family "{family.name}" is in "{family.mode}" mode but variables and '
|
||||
#FIXME f'families inside have the higher modes "{min_variable_mode}"')
|
||||
#FIXME raise DictConsistencyError(msg, 62, family.xmlfiles)
|
||||
|
||||
def _change_variable_mode(self,
|
||||
variable,
|
||||
family_mode: str,
|
||||
is_follower: bool,
|
||||
) -> None:
|
||||
if hasattr(variable, 'mode'):
|
||||
if variable.mode:
|
||||
variable_mode = variable.mode
|
||||
else:
|
||||
variable_mode = self.objectspace.rougailconfig['default_variable_mode']
|
||||
|
|
@ -263,28 +264,21 @@ class Annotator(Walk):
|
|||
f'but family has the higher family mode "{family_mode}"')
|
||||
raise DictConsistencyError(msg, 61, variable.xmlfiles)
|
||||
self._set_auto_mode(variable, family_mode)
|
||||
if not hasattr(variable, 'mode'):
|
||||
if not variable.mode:
|
||||
variable.mode = variable_mode
|
||||
|
||||
def dynamic_families(self):
|
||||
"""link dynamic families to object
|
||||
"""
|
||||
for family in self.get_families():
|
||||
if 'dynamic' not in vars(family):
|
||||
if family.type != 'dynamic':
|
||||
continue
|
||||
family.suffixes = self.objectspace.paths.get_variable(family.dynamic,
|
||||
family.namespace,
|
||||
xmlfiles=family.xmlfiles,
|
||||
allow_variable_namespace=True,
|
||||
force_path_prefix=family.path_prefix,
|
||||
add_path_prefix=True,
|
||||
)
|
||||
del family.dynamic
|
||||
if not family.suffixes.multi:
|
||||
family.variable = self.objectspace.paths[family.variable]
|
||||
if not family.variable.multi:
|
||||
msg = _(f'dynamic family "{family.name}" must be linked '
|
||||
f'to multi variable')
|
||||
raise DictConsistencyError(msg, 16, family.xmlfiles)
|
||||
for variable in family.variable.values():
|
||||
for variable in self.objectspace.parents[family.path]:
|
||||
if isinstance(variable, self.objectspace.family) and not variable.leadership:
|
||||
msg = _(f'dynamic family "{family.name}" cannot contains another family')
|
||||
raise DictConsistencyError(msg, 22, family.xmlfiles)
|
||||
|
|
@ -293,9 +287,7 @@ class Annotator(Walk):
|
|||
"""Convert variable help
|
||||
"""
|
||||
for family in self.get_families():
|
||||
if not hasattr(family, 'help'):
|
||||
if not family.help:
|
||||
continue
|
||||
if not hasattr(family, 'information'):
|
||||
family.information = self.objectspace.information(family.xmlfiles)
|
||||
family.information.help = family.help
|
||||
self.objectspace.informations.add(family.path, 'help', family.help)
|
||||
del family.help
|
||||
|
|
|
|||
|
|
@ -40,71 +40,6 @@ from jinja2 import Undefined, UndefinedError, DictLoader
|
|||
from jinja2.utils import missing
|
||||
|
||||
|
||||
class CollectUndefined(Undefined):
|
||||
def __init__(
|
||||
self,
|
||||
hint=None,
|
||||
obj=missing,
|
||||
name=None,
|
||||
exc=UndefinedError,
|
||||
subname=None,
|
||||
) -> None:
|
||||
self._undefined_hint = hint
|
||||
self._undefined_obj = obj
|
||||
self._undefined_name = name
|
||||
self._undefined_exception = exc
|
||||
if subname:
|
||||
full_name = subname + '.'
|
||||
else:
|
||||
full_name = ''
|
||||
full_name += self._undefined_name
|
||||
self.variables.add(full_name)
|
||||
self._undefined_full_name = full_name
|
||||
|
||||
def __getattr__(self, name):
|
||||
return CollectUndefined(name=name, subname=self._undefined_full_name)
|
||||
|
||||
|
||||
def get_jinja_variable_to_param(jinja_text,
|
||||
objectspace,
|
||||
obj,
|
||||
path_prefix,
|
||||
variable_name,
|
||||
variable_path,
|
||||
):
|
||||
CollectUndefined.variables = set()
|
||||
try:
|
||||
SandboxedEnvironment(loader=DictLoader({'tmpl': jinja_text}), undefined=CollectUndefined).get_template('tmpl').render()
|
||||
except UndefinedError as err:
|
||||
msg = _(f'error in jinja "{jinja_text}": {err}')
|
||||
raise DictConsistencyError(msg, 91, obj.xmlfiles) from err
|
||||
variables = list(CollectUndefined.variables)
|
||||
variables.sort()
|
||||
for variable in variables:
|
||||
new_param = objectspace.param(obj.xmlfiles)
|
||||
if variable in [variable_name, variable_path]:
|
||||
new_param.name = '__internal_key'
|
||||
new_param.type = 'string'
|
||||
new_param.text = variable
|
||||
else:
|
||||
new_param.name = variable
|
||||
new_param.text = variable
|
||||
try:
|
||||
set_variable_to_param(new_param,
|
||||
objectspace,
|
||||
None,
|
||||
obj.namespace,
|
||||
path_prefix,
|
||||
None,
|
||||
)
|
||||
except DictConsistencyError as err:
|
||||
if err.errno != 42:
|
||||
raise err from err
|
||||
continue
|
||||
new_param.type = 'variable'
|
||||
obj.param.append(new_param)
|
||||
|
||||
|
||||
CALC_MULTI = ('calc_value',
|
||||
'calc_list',
|
||||
'get_range',
|
||||
|
|
@ -127,9 +62,9 @@ class Annotator(TargetAnnotator, ParamAnnotator):
|
|||
level = 60
|
||||
def __init__(self,
|
||||
objectspace,
|
||||
functions,
|
||||
*args,
|
||||
):
|
||||
return
|
||||
self.objectspace = objectspace
|
||||
self.functions = copy(functions)
|
||||
self.functions.extend(self.objectspace.rougailconfig['internal_functions'])
|
||||
|
|
|
|||
|
|
@ -1,85 +0,0 @@
|
|||
"""Annotate group
|
||||
|
||||
Created by:
|
||||
EOLE (http://eole.orion.education.fr)
|
||||
Copyright (C) 2005-2018
|
||||
|
||||
Forked by:
|
||||
Cadoles (http://www.cadoles.com)
|
||||
Copyright (C) 2019-2021
|
||||
|
||||
Silique (https://www.silique.fr)
|
||||
Copyright (C) 2022-2023
|
||||
|
||||
distribued with GPL-2 or later license
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
"""
|
||||
from rougail.i18n import _
|
||||
from rougail.error import DictConsistencyError
|
||||
from rougail.utils import normalize_family
|
||||
from rougail.annotator.variable import Walk
|
||||
|
||||
|
||||
class Annotator(Walk):
|
||||
"""Annotate group
|
||||
"""
|
||||
level = 10
|
||||
def __init__(self,
|
||||
objectspace,
|
||||
*args,
|
||||
):
|
||||
if not hasattr(objectspace.space, 'variables'):
|
||||
return
|
||||
self.objectspace = objectspace
|
||||
self.convert_groups()
|
||||
|
||||
def convert_groups(self): # pylint: disable=C0111
|
||||
"""convert groups
|
||||
"""
|
||||
# store old leaders family name
|
||||
for family in self.get_families():
|
||||
if not isinstance(family, self.objectspace.family):
|
||||
continue
|
||||
if not family.leadership:
|
||||
continue
|
||||
if hasattr(family, 'dynamic'):
|
||||
msg = _(f'the family "{family.name}" cannot be leadership and dynamic together')
|
||||
raise DictConsistencyError(msg, 31, family.xmlfiles)
|
||||
if not hasattr(family, 'variable'):
|
||||
continue
|
||||
for idx, variable in enumerate(family.variable.values()):
|
||||
if idx == 0:
|
||||
# it's a leader
|
||||
if variable.multi is not True:
|
||||
msg = _(f'the variable "{variable.name}" in a leadership must be multi')
|
||||
raise DictConsistencyError(msg, 32, variable.xmlfiles)
|
||||
if variable.hidden:
|
||||
family.hidden = variable.hidden
|
||||
elif family.hidden:
|
||||
variable.hidden = family.hidden
|
||||
if variable.hidden:
|
||||
variable.frozen = True
|
||||
variable.force_default_on_freeze = True
|
||||
variable.hidden = None
|
||||
else:
|
||||
# it's a follower
|
||||
if family.hidden:
|
||||
variable.frozen = True
|
||||
variable.force_default_on_freeze = True
|
||||
if variable.multi is True:
|
||||
variable.multi = 'submulti'
|
||||
else:
|
||||
variable.multi = True
|
||||
|
|
@ -30,6 +30,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
from rougail.i18n import _
|
||||
from rougail.error import DictConsistencyError
|
||||
from rougail.annotator.variable import Walk
|
||||
from rougail.utils import Calculation
|
||||
|
||||
|
||||
PROPERTIES = ('hidden', 'frozen', 'force_default_on_freeze',
|
||||
|
|
@ -45,88 +46,98 @@ class Annotator(Walk):
|
|||
*args
|
||||
) -> None:
|
||||
self.objectspace = objectspace
|
||||
services = []
|
||||
if not self.objectspace.paths.has_path_prefix() and hasattr(self.objectspace.space, 'services'):
|
||||
services.append(self.objectspace.space.services)
|
||||
elif hasattr(self.objectspace.space, 'variables'):
|
||||
for path_prefix in self.objectspace.paths.get_path_prefixes():
|
||||
if path_prefix in self.objectspace.space.variables and \
|
||||
hasattr(self.objectspace.space.variables[path_prefix], 'services'):
|
||||
services.append(self.objectspace.space.variables[path_prefix].services)
|
||||
for service in services:
|
||||
self.convert_services(service)
|
||||
if hasattr(self.objectspace.space, 'variables'):
|
||||
# services = []
|
||||
# if not self.objectspace.paths.has_path_prefix() and hasattr(self.objectspace.space, 'services'):
|
||||
# services.append(self.objectspace.space.services)
|
||||
# elif hasattr(self.objectspace.space, 'variables'):
|
||||
# for path_prefix in self.objectspace.paths.get_path_prefixes():
|
||||
# if path_prefix in self.objectspace.space.variables and \
|
||||
# hasattr(self.objectspace.space.variables[path_prefix], 'services'):
|
||||
# services.append(self.objectspace.space.variables[path_prefix].services)
|
||||
if self.objectspace.paths:
|
||||
for family in self.get_families():
|
||||
#if family.path != 'services' and not family.path.startswith('services.'):
|
||||
if family.path != 'services':
|
||||
continue
|
||||
self.convert_services(family)
|
||||
self.convert_family()
|
||||
self.convert_variable()
|
||||
|
||||
def convert_property(self,
|
||||
variable,
|
||||
) -> None:
|
||||
"""convert properties
|
||||
"""
|
||||
# hidden variable is also frozen
|
||||
if isinstance(variable, self.objectspace.variable) and variable.hidden is True and \
|
||||
variable.name != self.objectspace.rougailconfig['auto_freeze_variable']:
|
||||
if not variable.auto_freeze and \
|
||||
not hasattr(variable, 'provider') and not hasattr(variable, 'supplier'):
|
||||
variable.frozen = True
|
||||
if not variable.auto_save and \
|
||||
not variable.auto_freeze and \
|
||||
'force_default_on_freeze' not in vars(variable) and \
|
||||
not hasattr(variable, 'provider') and not hasattr(variable, 'supplier'):
|
||||
variable.force_default_on_freeze = True
|
||||
if not hasattr(variable, 'properties'):
|
||||
variable.properties = []
|
||||
if 'mandatory' in vars(variable) and not variable.mandatory and variable.multi:
|
||||
# a multi could not have "None" has value
|
||||
# to permit it, just add mandatory="False"
|
||||
variable.properties.append('notempty')
|
||||
for prop in PROPERTIES:
|
||||
if hasattr(variable, prop):
|
||||
if getattr(variable, prop) is True:
|
||||
# for subprop in CONVERT_PROPERTIES.get(prop, [prop]):
|
||||
variable.properties.append(prop)
|
||||
setattr(variable, prop, None)
|
||||
if hasattr(variable, 'unique') and variable.unique != 'nil':
|
||||
if variable.unique == 'False' or variable.unique is False:
|
||||
variable.properties.append('notunique')
|
||||
else:
|
||||
variable.properties.append('unique')
|
||||
if hasattr(variable, 'mode') and variable.mode:
|
||||
variable.properties.append(variable.mode)
|
||||
variable.mode = None
|
||||
if 'force_store_value' in variable.properties and \
|
||||
'force_default_on_freeze' in variable.properties: # pragma: no cover
|
||||
# should not appened
|
||||
msg = _('cannot have auto_freeze or auto_save with the hidden '
|
||||
f'variable "{variable.name}"')
|
||||
raise DictConsistencyError(msg, 50, variable.xmlfiles)
|
||||
if not variable.properties:
|
||||
del variable.properties
|
||||
|
||||
def convert_services(self, services) -> None:
|
||||
"""convert services
|
||||
"""
|
||||
self.convert_property(services)
|
||||
for services_ in services.service.values():
|
||||
self.convert_property(services_)
|
||||
for service in vars(services_).values():
|
||||
if not isinstance(service, self.objectspace.family):
|
||||
continue
|
||||
self.convert_property(service)
|
||||
for family in service.family:
|
||||
self.convert_property(family)
|
||||
for variable in family.variable:
|
||||
self.convert_property(variable)
|
||||
self._convert_property(services)
|
||||
|
||||
def convert_family(self) -> None:
|
||||
"""convert families
|
||||
"""
|
||||
for family in self.get_families():
|
||||
self.convert_property(family)
|
||||
if family.path == 'services' or family.path.startswith('services.'):
|
||||
continue
|
||||
self._convert_property(family)
|
||||
|
||||
def convert_variable(self) -> None:
|
||||
"""convert variables
|
||||
"""
|
||||
for variable in self.get_variables():
|
||||
self.convert_property(variable)
|
||||
if variable.path.startswith('services.'):
|
||||
continue
|
||||
if variable.type == 'symlink':
|
||||
continue
|
||||
self._convert_variable_property(variable)
|
||||
|
||||
|
||||
|
||||
def _convert_variable_property(self,
|
||||
variable: dict,
|
||||
) -> None:
|
||||
"""convert properties
|
||||
"""
|
||||
path = variable.path
|
||||
self._convert_property(variable)
|
||||
if variable.hidden:
|
||||
# hidden variable is also frozen
|
||||
if variable.hidden is True:
|
||||
value = True
|
||||
else:
|
||||
datas = {'type': variable.hidden.type,
|
||||
variable.hidden.type: variable.hidden.value,
|
||||
}
|
||||
if variable.hidden.params:
|
||||
datas['params'] = variable.hidden.params
|
||||
value = Calculation('',
|
||||
'frozen',
|
||||
variable.path,
|
||||
datas,
|
||||
'',
|
||||
self.objectspace,
|
||||
False,
|
||||
)
|
||||
|
||||
self.objectspace.properties.add(path, 'frozen', value)
|
||||
if not variable.auto_save:
|
||||
# if auto_save, save calculated value
|
||||
self.objectspace.properties.add(path, 'force_default_on_freeze', True)
|
||||
if not variable.mandatory and variable.multi:
|
||||
# a multi could not have "None" has value
|
||||
# to permit it, just add mandatory="False"
|
||||
self.objectspace.properties.add(path, 'notempty', True)
|
||||
if variable.unique:
|
||||
self.objectspace.properties.add(path, 'unique', True)
|
||||
if variable.unique is False:
|
||||
self.objectspace.properties.add(path, 'notunique', True)
|
||||
if variable.auto_save:
|
||||
self.objectspace.properties.add(variable.path, 'force_store_value', True)
|
||||
|
||||
def _convert_property(self,
|
||||
obj: dict,
|
||||
) -> None:
|
||||
for prop in PROPERTIES:
|
||||
if not hasattr(obj, prop):
|
||||
continue
|
||||
value = getattr(obj, prop)
|
||||
if not value:
|
||||
continue
|
||||
self.objectspace.properties.add(obj.path, prop, value)
|
||||
if obj.mode:
|
||||
self.objectspace.properties.add(obj.path, obj.mode, True)
|
||||
|
|
|
|||
|
|
@ -33,7 +33,8 @@ from typing import Tuple
|
|||
from rougail.i18n import _
|
||||
from rougail.utils import normalize_family
|
||||
from rougail.error import DictConsistencyError
|
||||
from rougail.annotator.variable import CONVERT_OPTION
|
||||
#from rougail.annotator.variable import CONVERT_OPTION
|
||||
from tiramisu import PermissionsOption, UsernameOption
|
||||
try:
|
||||
import tiramisu4 as tiramisu
|
||||
except ModuleNotFoundError:
|
||||
|
|
@ -48,13 +49,6 @@ FORCE_INFORMATIONS = ['mode']
|
|||
|
||||
class Annotator:
|
||||
"""Manage service's object
|
||||
for example::
|
||||
<services>
|
||||
<service name="test">
|
||||
<service_access service='ntp'>
|
||||
</service_access>
|
||||
</service>
|
||||
</services>
|
||||
"""
|
||||
level = 20
|
||||
def __init__(self,
|
||||
|
|
@ -63,238 +57,373 @@ class Annotator:
|
|||
) -> None:
|
||||
self.objectspace = objectspace
|
||||
self.uniq_overrides = {}
|
||||
if 'network_type' not in self.objectspace.types:
|
||||
self.objectspace.types['network_type'] = self.objectspace.types['ip_type']
|
||||
#if 'network_type' not in self.objectspace.types:
|
||||
# self.objectspace.types['network_type'] = self.objectspace.types['ip_type']
|
||||
services = []
|
||||
if not self.objectspace.paths.has_path_prefix():
|
||||
if 1:
|
||||
#FIXME if not self.objectspace.paths.has_path_prefix():
|
||||
self.uniq_overrides[None] = []
|
||||
if hasattr(self.objectspace.space, 'services'):
|
||||
if not hasattr(self.objectspace.space.services, 'service'):
|
||||
del self.objectspace.space.services
|
||||
else:
|
||||
services.append((None, 'services', self.objectspace.space.services))
|
||||
elif hasattr(self.objectspace.space, 'variables'):
|
||||
for path_prefix in self.objectspace.paths.get_path_prefixes():
|
||||
self.uniq_overrides[path_prefix] = []
|
||||
root_path = f'{path_prefix}.services'
|
||||
if not path_prefix in self.objectspace.space.variables or \
|
||||
not hasattr(self.objectspace.space.variables[path_prefix], 'services'):
|
||||
continue
|
||||
if not hasattr(self.objectspace.space.variables[path_prefix].services, 'service'):
|
||||
del self.objectspace.space.variables[path_prefix].services
|
||||
else:
|
||||
services.append((path_prefix, root_path, self.objectspace.space.variables[path_prefix].services))
|
||||
for path_prefix, root_path, service in services:
|
||||
self.convert_services(path_prefix, root_path, service)
|
||||
# if hasattr(self.objectspace.space, 'services'):
|
||||
if self.objectspace.services:
|
||||
services.append((None, 'services', self.objectspace.services))
|
||||
#elif hasattr(self.objectspace.space, 'variables'):
|
||||
# for path_prefix in self.objectspace.paths.get_path_prefixes():
|
||||
# self.uniq_overrides[path_prefix] = []
|
||||
# root_path = f'{path_prefix}.services'
|
||||
# if not path_prefix in self.objectspace.space.variables or \
|
||||
# not hasattr(self.objectspace.space.variables[path_prefix], 'services'):
|
||||
# continue
|
||||
# if not hasattr(self.objectspace.space.variables[path_prefix].services, 'service'):
|
||||
# del self.objectspace.space.variables[path_prefix].services
|
||||
# else:
|
||||
# services.append((path_prefix, root_path, self.objectspace.space.variables[path_prefix].services))
|
||||
if services:
|
||||
self.objectspace.add_family('.',
|
||||
'services',
|
||||
'services',
|
||||
{'doc': 'services',
|
||||
'hidden': True,
|
||||
},
|
||||
[]
|
||||
)
|
||||
for path_prefix, root_path, service in services:
|
||||
self.convert_services(path_prefix, root_path, service)
|
||||
|
||||
def convert_services(self, path_prefix, root_path, services):
|
||||
"""convert services to variables
|
||||
"""
|
||||
services.hidden = True
|
||||
services.name = 'services'
|
||||
services.doc = 'services'
|
||||
services.path = root_path
|
||||
for service_name, service in services.service.items():
|
||||
service.name = normalize_family(service_name)
|
||||
activate_obj = self._generate_element('boolean',
|
||||
None,
|
||||
None,
|
||||
'activate',
|
||||
not service.disabled,
|
||||
service,
|
||||
f'{root_path}.{service.name}',
|
||||
path_prefix,
|
||||
)
|
||||
service.disabled = None
|
||||
dico = dict(vars(service))
|
||||
if 'type' not in dico:
|
||||
if service.manage:
|
||||
dico['type'] = service.type
|
||||
for service_name, service in services.items():
|
||||
n_service_name = normalize_family(service_name)
|
||||
path = f'{root_path}.{n_service_name}'
|
||||
self.objectspace.add_family(root_path,
|
||||
path,
|
||||
n_service_name,
|
||||
{'doc': service_name},
|
||||
service.xmlfiles,
|
||||
)
|
||||
for typ in ['ip', 'certificates', 'files']:
|
||||
if typ == 'ip':
|
||||
obj_typ = 'ips'
|
||||
else:
|
||||
dico['type'] = 'none'
|
||||
for elttype, values in dico.items():
|
||||
if elttype == 'servicelist':
|
||||
self.objectspace.paths.list_conditions[path_prefix].setdefault('servicelist',
|
||||
{}).setdefault(
|
||||
values,
|
||||
[]).append(activate_obj)
|
||||
continue
|
||||
obj_typ = typ
|
||||
values = getattr(self.objectspace, obj_typ)
|
||||
if path in values:
|
||||
obj_path = f'{path}.{typ}'
|
||||
if obj_path not in self.objectspace.paths:
|
||||
self.objectspace.add_family(path,
|
||||
obj_path,
|
||||
typ,
|
||||
{},
|
||||
service.xmlfiles,
|
||||
)
|
||||
function = getattr(self, f'convert_service_{typ}')
|
||||
for obj in values[path]:
|
||||
function(obj,
|
||||
obj_path,
|
||||
n_service_name,
|
||||
path_prefix,
|
||||
)
|
||||
self._generate_element('boolean',
|
||||
None,
|
||||
None,
|
||||
'activate',
|
||||
not service.disabled,
|
||||
service,
|
||||
path,
|
||||
path_prefix,
|
||||
)
|
||||
for elttype, values in service:
|
||||
if elttype in ERASED_ATTRIBUTES:
|
||||
continue
|
||||
if not service.manage and elttype not in ALLOW_ATTRIBUT_NOT_MANAGE and (elttype != 'type' or values != 'none'):
|
||||
if not service.manage and elttype not in ALLOW_ATTRIBUT_NOT_MANAGE and (elttype != 'type' or values is not None):
|
||||
msg = _(f'unmanage service cannot have "{elttype}"')
|
||||
raise DictConsistencyError(msg, 66, service.xmlfiles)
|
||||
if isinstance(values, (dict, list)):
|
||||
if elttype != 'ip':
|
||||
eltname = elttype + 's'
|
||||
else:
|
||||
eltname = elttype
|
||||
if hasattr(service, 'servicelist'):
|
||||
if isinstance(values, dict):
|
||||
for key, value in values.items():
|
||||
setattr(value, 'servicelist', service.servicelist)
|
||||
family = self._gen_family(eltname,
|
||||
f'{root_path}.{service.name}',
|
||||
service.xmlfiles,
|
||||
path_prefix,
|
||||
with_informations=False,
|
||||
)
|
||||
if isinstance(values, dict):
|
||||
values = list(values.values())
|
||||
family.family = self.make_group_from_elts(service_name,
|
||||
elttype,
|
||||
values,
|
||||
f'{root_path}.{service.name}.{eltname}',
|
||||
root_path,
|
||||
path_prefix,
|
||||
)
|
||||
setattr(service, elttype, family)
|
||||
else:
|
||||
if not hasattr(service, 'information'):
|
||||
service.information = self.objectspace.information(service.xmlfiles)
|
||||
setattr(service.information, elttype, values)
|
||||
service.path = f'{root_path}.{service.name}'
|
||||
manage = self._generate_element('boolean',
|
||||
None,
|
||||
None,
|
||||
'manage',
|
||||
service.manage,
|
||||
service,
|
||||
f'{root_path}.{service.name}',
|
||||
path_prefix,
|
||||
)
|
||||
service.variable = [activate_obj, manage]
|
||||
service.doc = service_name
|
||||
|
||||
def make_group_from_elts(self,
|
||||
service_name,
|
||||
elttype,
|
||||
elts,
|
||||
path,
|
||||
root_path,
|
||||
path_prefix,
|
||||
):
|
||||
"""Splits each objects into a group (and `OptionDescription`, in tiramisu terms)
|
||||
and build elements and its attributes (the `Options` in tiramisu terms)
|
||||
"""
|
||||
families = []
|
||||
listname = '{}list'.format(elttype)
|
||||
for elt in elts:
|
||||
# try to launch _update_xxxx() function
|
||||
update_elt = '_update_' + elttype
|
||||
if hasattr(self, update_elt):
|
||||
getattr(self, update_elt)(elt,
|
||||
service_name,
|
||||
path_prefix,
|
||||
if values:
|
||||
self.objectspace.informations.add(path, elttype, values)
|
||||
self.objectspace.add_variable(path,
|
||||
f'{path}.manage',
|
||||
'manage',
|
||||
{'type': 'boolean',
|
||||
'default': True,
|
||||
},
|
||||
service.xmlfiles,
|
||||
)
|
||||
c_name, subpath = self._get_name_path(elt,
|
||||
path,
|
||||
root_path,
|
||||
path_prefix,
|
||||
)
|
||||
family = self._gen_family(c_name,
|
||||
subpath.rsplit('.', 1)[0],
|
||||
elt.xmlfiles,
|
||||
path_prefix,
|
||||
|
||||
def convert_service_ip(self,
|
||||
ip: dict,
|
||||
subpath: str,
|
||||
service_name: str,
|
||||
path_prefix: str,
|
||||
) -> None:
|
||||
variable = self.objectspace.paths[ip.name]
|
||||
if variable.type not in ['ip', 'network', 'network_cidr']:
|
||||
msg = _(f'ip cannot be linked to "{variable.type}" variable "{ip.name}"')
|
||||
raise DictConsistencyError(msg, 70, ip.xmlfiles)
|
||||
if variable.type in ['ip', 'network_cidr'] and ip.netmask:
|
||||
msg = _(f'ip with ip_type "{variable.type}" must not have netmask')
|
||||
raise DictConsistencyError(msg, 59, ip.xmlfiles)
|
||||
if variable.type == 'network' and not ip.netmask:
|
||||
msg = _(f'ip with ip_type "{variable.type}" must have netmask')
|
||||
raise DictConsistencyError(msg, 64, ip.xmlfiles)
|
||||
if ip.netmask:
|
||||
netmask = self.objectspace.paths[ip.netmask]
|
||||
if netmask.type != 'netmask':
|
||||
msg = _(f'netmask in ip must have type "netmask", not "{netmask.type}"')
|
||||
raise DictConsistencyError(msg, 65, ip.xmlfiles)
|
||||
name = normalize_family(ip.name)
|
||||
path = f'{subpath}.{name}'
|
||||
self.objectspace.add_family(subpath,
|
||||
path,
|
||||
name,
|
||||
{'doc': ip.name},
|
||||
ip.xmlfiles,
|
||||
)
|
||||
self.objectspace.add_variable(path,
|
||||
f'{path}.name',
|
||||
'name',
|
||||
{'type': 'symlink',
|
||||
'opt': variable,
|
||||
},
|
||||
ip.xmlfiles,
|
||||
)
|
||||
family.variable = []
|
||||
if hasattr(elt, 'disabled'):
|
||||
disabled = elt.disabled
|
||||
else:
|
||||
disabled = False
|
||||
activate_obj = self._generate_element('boolean',
|
||||
None,
|
||||
None,
|
||||
'activate',
|
||||
not disabled,
|
||||
elt,
|
||||
subpath,
|
||||
path_prefix,
|
||||
)
|
||||
for key in dir(elt):
|
||||
if key.startswith('_') or key.endswith('_type') or key in ERASED_ATTRIBUTES2:
|
||||
continue
|
||||
value = getattr(elt, key)
|
||||
if key in [listname, 'servicelist']:
|
||||
self.objectspace.paths.list_conditions[path_prefix].setdefault(key,
|
||||
{}).setdefault(
|
||||
value,
|
||||
[]).append(activate_obj)
|
||||
continue
|
||||
if key == 'name':
|
||||
dtd_key_type = elttype + '_type'
|
||||
else:
|
||||
dtd_key_type = key + '_type'
|
||||
elt_type = getattr(elt, dtd_key_type, None)
|
||||
if elt_type:
|
||||
try:
|
||||
value = CONVERT_OPTION.get(elt_type, {}).get('func', str)(value)
|
||||
except ValueError as err:
|
||||
msg = _(f'"{value}" is not a valid "{elttype}": {err}')
|
||||
raise DictConsistencyError(msg, 93, elt.xmlfiles)
|
||||
if key not in FORCE_INFORMATIONS and elt_type:
|
||||
if elt_type == 'variable':
|
||||
elt_type = 'symlink'
|
||||
family.variable.append(self._generate_element(elt_type,
|
||||
dtd_key_type,
|
||||
elttype,
|
||||
key,
|
||||
value,
|
||||
elt,
|
||||
subpath,
|
||||
path_prefix,
|
||||
))
|
||||
else:
|
||||
setattr(family.information, key, value)
|
||||
|
||||
family.variable.append(activate_obj)
|
||||
families.append(family)
|
||||
return families
|
||||
|
||||
def _get_name_path(self,
|
||||
elt,
|
||||
path: str,
|
||||
root_path: str,
|
||||
path_prefix: str,
|
||||
) -> Tuple[str, str]:
|
||||
# create element name, if already exists, add _xx to be uniq
|
||||
if hasattr(elt, 'source') and elt.source:
|
||||
name = elt.source
|
||||
else:
|
||||
name = elt.name
|
||||
idx = 0
|
||||
while True:
|
||||
c_name = name
|
||||
if idx:
|
||||
c_name += f'_{idx}'
|
||||
subpath = '{}.{}'.format(path, normalize_family(c_name))
|
||||
try:
|
||||
self.objectspace.paths.get_family(subpath, root_path, path_prefix)
|
||||
except DictConsistencyError as err:
|
||||
if err.errno == 42:
|
||||
return c_name, subpath
|
||||
idx += 1
|
||||
|
||||
def _gen_family(self,
|
||||
name,
|
||||
subpath,
|
||||
xmlfiles,
|
||||
path_prefix,
|
||||
with_informations=True,
|
||||
):
|
||||
family = self.objectspace.family(xmlfiles)
|
||||
family.name = normalize_family(name)
|
||||
family.doc = name
|
||||
family.mode = None
|
||||
self.objectspace.paths.add_family('services',
|
||||
subpath,
|
||||
family,
|
||||
False,
|
||||
force_path_prefix=path_prefix,
|
||||
if ip.netmask:
|
||||
self.objectspace.add_variable(path,
|
||||
f'{path}.netmask',
|
||||
'netmask',
|
||||
{'type': 'symlink',
|
||||
'opt': self.objectspace.paths[ip.netmask],
|
||||
},
|
||||
ip.xmlfiles,
|
||||
)
|
||||
if with_informations:
|
||||
family.information = self.objectspace.information(xmlfiles)
|
||||
return family
|
||||
self._generate_element('boolean',
|
||||
None,
|
||||
None,
|
||||
'activate',
|
||||
True,
|
||||
#not service.disabled,
|
||||
ip,
|
||||
path,
|
||||
path_prefix,
|
||||
)
|
||||
|
||||
def convert_service_certificates(self,
|
||||
certificate: dict,
|
||||
subpath: str,
|
||||
service_name: str,
|
||||
path_prefix: str,
|
||||
) -> None:
|
||||
if isinstance(certificate.name, dict):
|
||||
variable = self.objectspace.paths[certificate.name['name']]
|
||||
if variable.type != 'filename':
|
||||
msg = _(f'certificate cannot be linked to "{variable.type}" variable "{ip.name}"')
|
||||
raise Exception(msg)
|
||||
# raise DictConsistencyError(msg, 70, ip.xmlfiles)
|
||||
name_obj = {'type': 'symlink',
|
||||
'opt': variable,
|
||||
}
|
||||
else:
|
||||
name = certificate.name
|
||||
name_obj = {'default': name}
|
||||
name = normalize_family(name)
|
||||
path = f'{subpath}.{name}'
|
||||
self.objectspace.add_family(subpath,
|
||||
path,
|
||||
name,
|
||||
{'doc': name},
|
||||
certificate.xmlfiles,
|
||||
)
|
||||
self.objectspace.add_variable(path,
|
||||
f'{path}.name',
|
||||
'name',
|
||||
name_obj,
|
||||
certificate.xmlfiles,
|
||||
)
|
||||
self.objectspace.informations.add(path, 'authority', certificate.authority)
|
||||
for typ in ['provider', 'format', 'type']:
|
||||
value = getattr(certificate, typ)
|
||||
if value:
|
||||
self.objectspace.informations.add(path, typ, value)
|
||||
if certificate.mode:
|
||||
PermissionsOption('', '', default=certificate.mode)
|
||||
self.objectspace.informations.add(path, 'mode', certificate.mode)
|
||||
#
|
||||
for typ in ['owner', 'group']:
|
||||
value = getattr(certificate, typ)
|
||||
if value is None:
|
||||
continue
|
||||
if isinstance(value, str):
|
||||
UsernameOption('', '', default=value)
|
||||
new_variable = {'type': 'unix_user',
|
||||
'default': value}
|
||||
else:
|
||||
new_variable = {'type': 'symlink',
|
||||
'opt': self.objectspace.paths[value['name']],
|
||||
}
|
||||
self.objectspace.add_variable(path,
|
||||
f'{path}.{typ}',
|
||||
typ,
|
||||
new_variable,
|
||||
certificate.xmlfiles,
|
||||
)
|
||||
#
|
||||
if certificate.domain is None:
|
||||
certificate.domain = self.objectspace.rougailconfig['default_certificate_domain']
|
||||
for typ in ['server', 'domain']:
|
||||
value = getattr(certificate, typ)
|
||||
if value is None:
|
||||
continue
|
||||
value = {'type': 'symlink',
|
||||
'opt': self.objectspace.paths[value],
|
||||
}
|
||||
self.objectspace.add_variable(path,
|
||||
f'{path}.{typ}',
|
||||
typ,
|
||||
value,
|
||||
certificate.xmlfiles,
|
||||
)
|
||||
self._generate_element('boolean',
|
||||
None,
|
||||
None,
|
||||
'activate',
|
||||
True,
|
||||
#not service.disabled,
|
||||
certificate,
|
||||
path,
|
||||
path_prefix,
|
||||
)
|
||||
|
||||
def convert_service_files(self,
|
||||
file: dict,
|
||||
subpath: str,
|
||||
service_name: str,
|
||||
path_prefix: str,
|
||||
) -> None:
|
||||
if isinstance(file.source, dict):
|
||||
if file.source['type'] != 'variable':
|
||||
raise Exception('pfff')
|
||||
source_obj = {'type': 'symlink',
|
||||
'opt': self.objectspace.paths[file.source['name']],
|
||||
}
|
||||
else:
|
||||
source_obj = {'type': 'filename',
|
||||
'default': file.name,
|
||||
}
|
||||
if not file.variable:
|
||||
if not file.source:
|
||||
file.source = basename(file.name)
|
||||
elif not file.source:
|
||||
msg = _(f'attribute "source" is mandatory for the file "{file.name}" in '
|
||||
f'"({service_name})"')
|
||||
raise DictConsistencyError(msg, 34, file_.xmlfiles)
|
||||
name, path = self.get_name_path(file, subpath)
|
||||
self.objectspace.add_family(subpath,
|
||||
path,
|
||||
name,
|
||||
{'doc': name},
|
||||
file.xmlfiles,
|
||||
)
|
||||
self.objectspace.add_variable(path,
|
||||
f'{path}.name',
|
||||
'name',
|
||||
{'type': 'filename',
|
||||
'default': file.name,
|
||||
},
|
||||
file.xmlfiles,
|
||||
)
|
||||
#
|
||||
self.objectspace.add_variable(path,
|
||||
f'{path}.source',
|
||||
'source',
|
||||
source_obj,
|
||||
file.xmlfiles,
|
||||
)
|
||||
#
|
||||
if file.mode:
|
||||
PermissionsOption('', '', default=file.mode)
|
||||
self.objectspace.informations.add(path, 'mode', file.mode)
|
||||
#
|
||||
if file.engine:
|
||||
self.objectspace.informations.add(path, 'engine', file.engine)
|
||||
#
|
||||
if file.included != 'no':
|
||||
self.objectspace.informations.add(path, 'included', file.included)
|
||||
#
|
||||
for typ in ['owner', 'group']:
|
||||
value = getattr(file, typ)
|
||||
if value is None:
|
||||
continue
|
||||
if isinstance(value, str):
|
||||
UsernameOption('', '', default=value)
|
||||
new_variable = {'type': 'unix_user',
|
||||
'default': value}
|
||||
else:
|
||||
new_variable = {'type': 'symlink',
|
||||
'opt': self.objectspace.paths[value['name']],
|
||||
}
|
||||
self.objectspace.add_variable(path,
|
||||
f'{path}.{typ}',
|
||||
typ,
|
||||
new_variable,
|
||||
file.xmlfiles,
|
||||
)
|
||||
#
|
||||
self._generate_element('boolean',
|
||||
None,
|
||||
None,
|
||||
'activate',
|
||||
True,
|
||||
#not service.disabled,
|
||||
file,
|
||||
path,
|
||||
path_prefix,
|
||||
)
|
||||
|
||||
def convert_service_overrides(self,
|
||||
override: dict,
|
||||
subpath: str,
|
||||
service_name: str,
|
||||
path_prefix: str,
|
||||
) -> None:
|
||||
name, path = self.get_name_path(override, subpath)
|
||||
self.objectspace.add_family(subpath,
|
||||
path,
|
||||
name,
|
||||
{'doc': name},
|
||||
override.xmlfiles,
|
||||
)
|
||||
self.objectspace.add_variable(path,
|
||||
f'{path}.name',
|
||||
'name',
|
||||
{'type': 'filename',
|
||||
'default': override.name,
|
||||
},
|
||||
override.xmlfiles,
|
||||
)
|
||||
#
|
||||
if override.source:
|
||||
self.objectspace.add_variable(path,
|
||||
f'{path}.source',
|
||||
'source',
|
||||
{'type': 'filename',
|
||||
'default': override.source,
|
||||
},
|
||||
override.xmlfiles,
|
||||
)
|
||||
#
|
||||
#
|
||||
if override.engine:
|
||||
self.objectspace.informations.add(path, 'engine', override.engine)
|
||||
#
|
||||
self._generate_element('boolean',
|
||||
None,
|
||||
None,
|
||||
'activate',
|
||||
True,
|
||||
#not service.disabled,
|
||||
override,
|
||||
path,
|
||||
path_prefix,
|
||||
)
|
||||
|
||||
def _generate_element(self,
|
||||
type_,
|
||||
|
|
@ -303,13 +432,13 @@ class Annotator:
|
|||
key,
|
||||
value,
|
||||
elt,
|
||||
path,
|
||||
subpath,
|
||||
path_prefix,
|
||||
): # pylint: disable=R0913
|
||||
variable = self.objectspace.variable(elt.xmlfiles)
|
||||
variable.name = normalize_family(key)
|
||||
variable.mode = None
|
||||
variable.type = type_
|
||||
name = normalize_family(key)
|
||||
variable_obj = {'type': type_,
|
||||
'xmlfiles': elt.xmlfiles
|
||||
}
|
||||
if type_ == 'symlink':
|
||||
variable.opt = self.objectspace.paths.get_variable(value,
|
||||
self.objectspace.rougailconfig['variable_namespace'],
|
||||
|
|
@ -325,15 +454,21 @@ class Annotator:
|
|||
raise DictConsistencyError(msg, 58, elt.xmlfiles)
|
||||
|
||||
else:
|
||||
variable.doc = key
|
||||
variable.default = value
|
||||
variable.namespace = 'services'
|
||||
self.objectspace.paths.add_variable('services',
|
||||
path,
|
||||
variable,
|
||||
force_path_prefix=path_prefix
|
||||
)
|
||||
return variable
|
||||
variable_obj['description'] = key
|
||||
variable_obj['default'] = value
|
||||
path = f'{subpath}.{name}'
|
||||
self.objectspace.add_variable(subpath,
|
||||
path,
|
||||
name,
|
||||
variable_obj,
|
||||
elt.xmlfiles,
|
||||
)
|
||||
# self.objectspace.paths.add_variable('services',
|
||||
# path,
|
||||
# variable,
|
||||
# force_path_prefix=path_prefix
|
||||
# )
|
||||
return self.objectspace.paths[path]
|
||||
|
||||
def _update_override(self,
|
||||
override,
|
||||
|
|
@ -363,37 +498,6 @@ class Annotator:
|
|||
f'"({service_name})"')
|
||||
raise DictConsistencyError(msg, 34, file_.xmlfiles)
|
||||
|
||||
def _update_ip(self,
|
||||
ip,
|
||||
service_name,
|
||||
path_prefix,
|
||||
) -> None:
|
||||
variable = self.objectspace.paths.get_variable(ip.name,
|
||||
ip.namespace,
|
||||
xmlfiles=ip.xmlfiles,
|
||||
force_path_prefix=path_prefix,
|
||||
add_path_prefix=True,
|
||||
)
|
||||
if variable.type not in ['ip', 'network', 'network_cidr']:
|
||||
msg = _(f'ip cannot be linked to "{variable.type}" variable "{ip.name}"')
|
||||
raise DictConsistencyError(msg, 70, ip.xmlfiles)
|
||||
if variable.type in ['ip', 'network_cidr'] and hasattr(ip, 'netmask'):
|
||||
msg = _(f'ip with ip_type "{variable.type}" must not have netmask')
|
||||
raise DictConsistencyError(msg, 59, ip.xmlfiles)
|
||||
if variable.type == 'network' and not hasattr(ip, 'netmask'):
|
||||
msg = _(f'ip with ip_type "{variable.type}" must have netmask')
|
||||
raise DictConsistencyError(msg, 64, ip.xmlfiles)
|
||||
if hasattr(ip, 'netmask'):
|
||||
netmask = self.objectspace.paths.get_variable(ip.netmask,
|
||||
ip.namespace,
|
||||
xmlfiles=ip.xmlfiles,
|
||||
force_path_prefix=path_prefix,
|
||||
add_path_prefix=True,
|
||||
)
|
||||
if netmask.type != 'netmask':
|
||||
msg = _(f'netmask in ip must have type "netmask", not "{netmask.type}"')
|
||||
raise DictConsistencyError(msg, 65, ip.xmlfiles)
|
||||
|
||||
def _update_certificate(self,
|
||||
certificate,
|
||||
certificate_name,
|
||||
|
|
@ -418,3 +522,25 @@ class Annotator:
|
|||
if variable.type != 'domainname':
|
||||
msg = _(f'the certificate "{certificate.name}" has an attribute "domain" linked with a "{variable.type}" variable ("{certificate.domain}"), but must be a "domainename" variable')
|
||||
raise DictConsistencyError(msg, 94, certificate.xmlfiles)
|
||||
|
||||
def get_name_path(self,
|
||||
elt,
|
||||
subpath: str,
|
||||
) -> Tuple[str, str]:
|
||||
# create element name, if already exists, add _xx to be uniq
|
||||
if hasattr(elt, 'source') and elt.source:
|
||||
name = elt.source
|
||||
if isinstance(name, dict):
|
||||
name = name['name']
|
||||
else:
|
||||
name = elt.name
|
||||
name = normalize_family(name)
|
||||
idx = 0
|
||||
while True:
|
||||
c_name = name
|
||||
if idx:
|
||||
c_name += f'_{idx}'
|
||||
path = f'{subpath}.{c_name}'
|
||||
if path not in self.objectspace.families:
|
||||
return c_name, path
|
||||
idx += 1
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ from rougail.annotator.variable import Walk
|
|||
|
||||
from rougail.i18n import _
|
||||
from rougail.error import DictConsistencyError
|
||||
from rougail.utils import Calculation
|
||||
|
||||
|
||||
class Annotator(Walk): # pylint: disable=R0903
|
||||
"""Annotate value
|
||||
|
|
@ -40,7 +42,7 @@ class Annotator(Walk): # pylint: disable=R0903
|
|||
objectspace,
|
||||
*args,
|
||||
) -> None:
|
||||
if not hasattr(objectspace.space, 'variables'):
|
||||
if not objectspace.paths:
|
||||
return
|
||||
self.objectspace = objectspace
|
||||
self.convert_value()
|
||||
|
|
@ -50,52 +52,52 @@ class Annotator(Walk): # pylint: disable=R0903
|
|||
"""convert value
|
||||
"""
|
||||
for variable in self.get_variables():
|
||||
if variable.type == 'symlink':
|
||||
continue
|
||||
self._convert_value(variable)
|
||||
|
||||
def _convert_value(self,
|
||||
variable,
|
||||
variable: dict,
|
||||
) -> None:
|
||||
multi = self.objectspace.multis.get(variable.path, False)
|
||||
# a boolean must have value, the default value is "True"
|
||||
if not hasattr(variable, 'value') and variable.type == 'boolean':
|
||||
new_value = self.objectspace.value(variable.xmlfiles)
|
||||
new_value.name = True
|
||||
new_value.type = 'boolean'
|
||||
variable.value = [new_value]
|
||||
# if the variable is mandatory and doesn't have any value
|
||||
# then the variable's mode is set to 'basic'
|
||||
# variable with default value is mandatory
|
||||
if hasattr(variable, 'value') and variable.value:
|
||||
has_value = True
|
||||
for value in variable.value:
|
||||
if value.type == 'calculation' or value.type == 'nil':
|
||||
has_value = False
|
||||
break
|
||||
if has_value and 'mandatory' not in vars(variable):
|
||||
# if has value without any calculation
|
||||
variable.mandatory = True
|
||||
if not hasattr(variable, 'value'):
|
||||
if variable.type == 'boolean' and \
|
||||
multi is False and \
|
||||
variable.default is None:
|
||||
variable.default = True
|
||||
|
||||
if variable.default is None:
|
||||
return
|
||||
if variable.value[0].type == 'calculation':
|
||||
variable.default = variable.value[0]
|
||||
elif variable.multi:
|
||||
if self.objectspace.paths.is_follower(variable):
|
||||
if variable.multi != 'submulti' and len(variable.value) != 1:
|
||||
has_value = False
|
||||
if isinstance(variable.default, Calculation):
|
||||
pass
|
||||
# variable.default = variable.default.to_function(self.functions)
|
||||
elif isinstance(variable.default, list):
|
||||
if not multi:
|
||||
raise Exception('pfff')
|
||||
if variable.path in self.objectspace.followers:
|
||||
if multi != 'submulti' and len(variable.default) != 1:
|
||||
msg = _(f'the follower "{variable.name}" without multi attribute can only have one value')
|
||||
raise DictConsistencyError(msg, 87, variable.xmlfiles)
|
||||
else:
|
||||
variable.default = [value.name for value in variable.value]
|
||||
if not self.objectspace.paths.is_leader(variable):
|
||||
if variable.multi == 'submulti':
|
||||
variable.default_multi = [value.name for value in variable.value]
|
||||
# else:
|
||||
# variable.default = [value.name for value in variable.default]
|
||||
if variable.path not in self.objectspace.leaders:
|
||||
if multi == 'submulti':
|
||||
self.objectspace.default_multi[variable.path] = variable.default #[value.name for value in variable.value]
|
||||
else:
|
||||
variable.default_multi = variable.value[0].name
|
||||
self.objectspace.default_multi[variable.path] = variable.default[0] #.name
|
||||
has_value = True
|
||||
elif variable.multi:
|
||||
#msg = _(f'the none multi variable "{variable.name}" cannot have '
|
||||
# 'more than one value')
|
||||
#raise DictConsistencyError(msg, 68, variable.xmlfiles)
|
||||
raise Exception('pfff')
|
||||
else:
|
||||
if len(variable.value) > 1:
|
||||
msg = _(f'the none multi variable "{variable.name}" cannot have '
|
||||
'more than one value')
|
||||
raise DictConsistencyError(msg, 68, variable.xmlfiles)
|
||||
variable.default = variable.value[0].name
|
||||
del variable.value
|
||||
has_value = True
|
||||
# variable with default value is mandatory
|
||||
if has_value and variable.mandatory is None:
|
||||
# if has value without any calculation
|
||||
variable.mandatory = True
|
||||
|
||||
def add_choice_nil(self) -> None:
|
||||
"""A variable with type "Choice" that is not mandatory must has "nil" value
|
||||
|
|
@ -104,11 +106,11 @@ class Annotator(Walk): # pylint: disable=R0903
|
|||
if variable.type != 'choice':
|
||||
continue
|
||||
is_none = False
|
||||
for choice in variable.choice:
|
||||
if choice.type == 'nil':
|
||||
if isinstance(variable.choices, Calculation):
|
||||
continue
|
||||
for choice in variable.choices:
|
||||
if choice is None:
|
||||
is_none = True
|
||||
break
|
||||
if not variable.mandatory and not is_none:
|
||||
choice = self.objectspace.choice(variable.xmlfiles)
|
||||
choice.name = None
|
||||
choice.type = 'nil'
|
||||
variable.choice.append(choice)
|
||||
variable.choices.append(None)
|
||||
|
|
|
|||
|
|
@ -30,26 +30,26 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
|
||||
from rougail.i18n import _
|
||||
from rougail.error import DictConsistencyError
|
||||
from rougail.objspace import convert_boolean, get_variables
|
||||
from rougail.objspace import convert_boolean #, get_variables
|
||||
from rougail.utils import Calculation
|
||||
|
||||
|
||||
CONVERT_OPTION = {'number': dict(opttype="IntOption", func=int),
|
||||
CONVERT_OPTION = {'string': dict(opttype="StrOption"),
|
||||
'number': dict(opttype="IntOption", func=int),
|
||||
'float': dict(opttype="FloatOption", func=float),
|
||||
'choice': dict(opttype="ChoiceOption"),
|
||||
'string': dict(opttype="StrOption"),
|
||||
'password': dict(opttype="PasswordOption"),
|
||||
'boolean': dict(opttype="BoolOption", func=convert_boolean),
|
||||
'secret': dict(opttype="PasswordOption"),
|
||||
'mail': dict(opttype="EmailOption"),
|
||||
'boolean': dict(opttype="BoolOption", func=convert_boolean),
|
||||
'symlink': dict(opttype="SymLinkOption"),
|
||||
'filename': dict(opttype="FilenameOption"),
|
||||
'date': dict(opttype="DateOption"),
|
||||
'unix_user': dict(opttype="UsernameOption"),
|
||||
'ip': dict(opttype="IPOption", initkwargs={'allow_reserved': True}),
|
||||
'cidr': dict(opttype="IPOption", initkwargs={'cidr': True}),
|
||||
'local_ip': dict(opttype="IPOption", initkwargs={'private_only': True,
|
||||
'warnings_only': True}),
|
||||
'netmask': dict(opttype="NetmaskOption"),
|
||||
'network': dict(opttype="NetworkOption"),
|
||||
'network_cidr': dict(opttype="NetworkOption", initkwargs={'cidr': True}),
|
||||
'broadcast': dict(opttype="BroadcastOption"),
|
||||
'netbios': dict(opttype="DomainnameOption", initkwargs={'type': 'netbios',
|
||||
'warnings_only': True}),
|
||||
|
|
@ -61,9 +61,10 @@ CONVERT_OPTION = {'number': dict(opttype="IntOption", func=int),
|
|||
'allow_without_dot': True}),
|
||||
'port': dict(opttype="PortOption", initkwargs={'allow_private': True, 'allow_protocol': True}),
|
||||
'mac': dict(opttype="MACOption"),
|
||||
'cidr': dict(opttype="IPOption", initkwargs={'cidr': True}),
|
||||
'network_cidr': dict(opttype="NetworkOption", initkwargs={'cidr': True}),
|
||||
'unix_permissions': dict(opttype="PermissionsOption", initkwargs={'warnings_only': True}, func=int),
|
||||
'choice': dict(opttype="ChoiceOption"),
|
||||
#
|
||||
'symlink': dict(opttype="SymLinkOption"),
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -75,56 +76,58 @@ class Walk:
|
|||
def get_variables(self):
|
||||
"""Iter all variables from the objectspace
|
||||
"""
|
||||
yield from get_variables(self.objectspace)
|
||||
for path in self.objectspace.variables:
|
||||
yield self.objectspace.paths[path]
|
||||
# yield from get_variables(self.objectspace)
|
||||
|
||||
def get_families(self,
|
||||
with_parent: bool=False,
|
||||
):
|
||||
def get_families(self):
|
||||
"""Iter all families from the objectspace
|
||||
"""
|
||||
for family in self.objectspace.space.variables.values():
|
||||
yield from self._get_families(family, None, with_parent)
|
||||
|
||||
def _get_families(self,
|
||||
family: 'self.objectspace.family',
|
||||
old_family: 'self.objectspace.family',
|
||||
with_parent: bool,
|
||||
):
|
||||
if with_parent:
|
||||
yield family, old_family,
|
||||
if hasattr(family, 'variable'):
|
||||
if not with_parent:
|
||||
yield family
|
||||
for fam in family.variable.values():
|
||||
if isinstance(fam, self.objectspace.family):
|
||||
yield from self._get_families(fam, family, with_parent)
|
||||
if hasattr(family, 'variables'):
|
||||
for fam in family.variables.values():
|
||||
yield from self._get_families(fam, family, with_parent)
|
||||
|
||||
def get_constraints(self,
|
||||
create: bool=False,
|
||||
path_prefix: str=None,
|
||||
):
|
||||
if not self.objectspace.paths.has_path_prefix():
|
||||
if hasattr(self.objectspace.space, 'constraints'):
|
||||
yield None, self.objectspace.space.constraints
|
||||
elif create:
|
||||
self.objectspace.space.constraints = self.objectspace.constraints(None)
|
||||
yield None, self.objectspace.space.constraints
|
||||
else:
|
||||
if path_prefix:
|
||||
path_prefixes = [path_prefix]
|
||||
else:
|
||||
path_prefixes = self.objectspace.paths.get_path_prefixes()
|
||||
for path_prefix in path_prefixes:
|
||||
if hasattr(self.objectspace.space, 'variables') and \
|
||||
path_prefix in self.objectspace.space.variables and \
|
||||
hasattr(self.objectspace.space.variables[path_prefix], 'constraints'):
|
||||
yield path_prefix, self.objectspace.space.variables[path_prefix].constraints
|
||||
elif create:
|
||||
self.objectspace.space.variables[path_prefix].constraints = self.objectspace.constraints(None)
|
||||
yield path_prefix, self.objectspace.space.variables[path_prefix].constraints
|
||||
for path in self.objectspace.families:
|
||||
yield self.objectspace.paths[path]
|
||||
# for family in self.objectspace.space.variables.values():
|
||||
# yield from self._get_families(family, None, with_parent)
|
||||
#
|
||||
# def _get_families(self,
|
||||
# family: 'self.objectspace.family',
|
||||
# old_family: 'self.objectspace.family',
|
||||
# with_parent: bool,
|
||||
# ):
|
||||
# if with_parent:
|
||||
# yield family, old_family,
|
||||
# if hasattr(family, 'variable'):
|
||||
# if not with_parent:
|
||||
# yield family
|
||||
# for fam in family.variable.values():
|
||||
# if isinstance(fam, self.objectspace.family):
|
||||
# yield from self._get_families(fam, family, with_parent)
|
||||
# if hasattr(family, 'variables'):
|
||||
# for fam in family.variables.values():
|
||||
# yield from self._get_families(fam, family, with_parent)
|
||||
#
|
||||
# def get_constraints(self,
|
||||
# create: bool=False,
|
||||
# path_prefix: str=None,
|
||||
# ):
|
||||
# if not self.objectspace.paths.has_path_prefix():
|
||||
# if hasattr(self.objectspace.space, 'constraints'):
|
||||
# yield None, self.objectspace.space.constraints
|
||||
# elif create:
|
||||
# self.objectspace.space.constraints = self.objectspace.constraints(None)
|
||||
# yield None, self.objectspace.space.constraints
|
||||
# else:
|
||||
# if path_prefix:
|
||||
# path_prefixes = [path_prefix]
|
||||
# else:
|
||||
# path_prefixes = self.objectspace.paths.get_path_prefixes()
|
||||
# for path_prefix in path_prefixes:
|
||||
# if hasattr(self.objectspace.space, 'variables') and \
|
||||
# path_prefix in self.objectspace.space.variables and \
|
||||
# hasattr(self.objectspace.space.variables[path_prefix], 'constraints'):
|
||||
# yield path_prefix, self.objectspace.space.variables[path_prefix].constraints
|
||||
# elif create:
|
||||
# self.objectspace.space.variables[path_prefix].constraints = self.objectspace.constraints(None)
|
||||
# yield path_prefix, self.objectspace.space.variables[path_prefix].constraints
|
||||
|
||||
|
||||
class Annotator(Walk): # pylint: disable=R0903
|
||||
|
|
@ -135,7 +138,7 @@ class Annotator(Walk): # pylint: disable=R0903
|
|||
objectspace,
|
||||
*args,
|
||||
):
|
||||
if not hasattr(objectspace.space, 'variables'):
|
||||
if not objectspace.paths:
|
||||
return
|
||||
self.objectspace = objectspace
|
||||
self.forbidden_name = ['services', self.objectspace.rougailconfig['variable_namespace']]
|
||||
|
|
@ -149,83 +152,72 @@ class Annotator(Walk): # pylint: disable=R0903
|
|||
"""convert variable
|
||||
"""
|
||||
for variable in self.get_variables():
|
||||
if variable.type == 'symlink':
|
||||
continue
|
||||
self._convert_variable(variable)
|
||||
|
||||
def _convert_variable(self,
|
||||
variable,
|
||||
variable: dict,
|
||||
) -> None:
|
||||
if variable.namespace == self.objectspace.rougailconfig['variable_namespace'] and \
|
||||
variable.name in self.forbidden_name:
|
||||
msg = _(f'the name of the variable "{variable.name}" cannot be the same as the name'
|
||||
' of a namespace')
|
||||
raise DictConsistencyError(msg, 54, variable.xmlfiles)
|
||||
if variable.type != 'symlink' and not hasattr(variable, 'description'):
|
||||
# variable without description: description is the name
|
||||
if not variable.description:
|
||||
variable.description = variable.name
|
||||
if hasattr(variable, 'value'):
|
||||
for idx, value in enumerate(variable.value):
|
||||
if not hasattr(value, 'name') and not hasattr(value, 'type'):
|
||||
msg = f'variable "{variable.name}" has a value without text, if you want the value None, set value type to nil'
|
||||
raise DictConsistencyError(msg, 95, value.xmlfiles)
|
||||
if not hasattr(value, 'type'):
|
||||
value.type = variable.type
|
||||
if hasattr(value, 'name'):
|
||||
try:
|
||||
value.name = CONVERT_OPTION.get(value.type, {}).get('func', str)(value.name)
|
||||
except Exception as err:
|
||||
msg = _(f'the variable "{variable.name}" has an incorrect value "{value.name}" with "{variable.type}" type')
|
||||
raise DictConsistencyError(msg, 88, variable.xmlfiles)
|
||||
else:
|
||||
value.name = None
|
||||
if not variable.value:
|
||||
del variable.value
|
||||
if hasattr(variable, 'choice'):
|
||||
if variable.type != 'choice':
|
||||
msg = _(f'choice for the variable "{variable.name}" not allowed with "{variable.type}" type')
|
||||
raise DictConsistencyError(msg, 3, variable.xmlfiles)
|
||||
values = []
|
||||
choice_type = None
|
||||
for choice in variable.choice:
|
||||
if choice_type == 'variable':
|
||||
msg = _(f'only one "variable" choice is allowed '
|
||||
f'the variable "{variable.name}"')
|
||||
raise DictConsistencyError(msg, 5, choice.xmlfiles)
|
||||
if choice.type == 'nil':
|
||||
choice.name = None
|
||||
elif choice.type == 'space':
|
||||
choice.name = ' '
|
||||
elif choice.type == 'variable':
|
||||
choice.name = self.objectspace.paths.get_variable(choice.name,
|
||||
variable.namespace,
|
||||
force_path_prefix=variable.path_prefix,
|
||||
)
|
||||
if not choice.name.multi:
|
||||
msg = _(f'only multi "variable" is allowed for a choice '
|
||||
f'of variable "{variable.name}"')
|
||||
raise DictConsistencyError(msg, 6, choice.xmlfiles)
|
||||
else:
|
||||
if not hasattr(choice, 'name'):
|
||||
msg = _(f'choice for variable "{variable.name}" must have a value')
|
||||
raise DictConsistencyError(msg, 14, choice.xmlfiles)
|
||||
choice.name = CONVERT_OPTION.get(choice.type, {}).get('func', str)(choice.name)
|
||||
if choice_type is None:
|
||||
choice_type = choice.type
|
||||
values.append(choice.name)
|
||||
if choice_type not in ['function', 'variable'] and hasattr(variable, 'value'):
|
||||
for value in variable.value:
|
||||
if value.name not in values:
|
||||
msg = _(f'value "{value.name}" of variable "{variable.name}" is not in list '
|
||||
f'of all expected values ({values})')
|
||||
raise DictConsistencyError(msg, 15, value.xmlfiles)
|
||||
ref_choice = variable.choice[0]
|
||||
self.objectspace.paths.set_valid_enums(variable.path,
|
||||
values,
|
||||
variable.path_prefix,
|
||||
)
|
||||
elif variable.type == 'choice':
|
||||
msg = _(f'choice is mandatory for the variable "{variable.name}" with choice type')
|
||||
raise DictConsistencyError(msg, 4, variable.xmlfiles)
|
||||
variable.doc = variable.description
|
||||
del variable.description
|
||||
if variable.path in self.objectspace.followers:
|
||||
if not variable.multi:
|
||||
self.objectspace.multis[variable.path] = True
|
||||
else:
|
||||
self.objectspace.multis[variable.path] = 'submulti'
|
||||
if self.objectspace.paths[variable.path.rsplit('.', 1)[0]].hidden:
|
||||
self.objectspace.properties.append(variable.path, 'frozen')
|
||||
self.objectspace.properties.append(variable.path, 'force_default_on_freeze')
|
||||
elif variable.multi:
|
||||
self.objectspace.multis[variable.path] = True
|
||||
if variable.path in self.objectspace.leaders:
|
||||
if not self.objectspace.multis.get(variable.path, False):
|
||||
msg = _(f'the variable "{variable.name}" in a leadership must be multi')
|
||||
raise DictConsistencyError(msg, 32, variable.xmlfiles)
|
||||
family = self.objectspace.paths[variable.path.rsplit('.', 1)[0]]
|
||||
if variable.hidden:
|
||||
family.hidden = variable.hidden
|
||||
elif family.hidden:
|
||||
variable.hidden = family.hidden
|
||||
if variable.hidden:
|
||||
self.objectspace.properties.append(variable.path, 'frozen')
|
||||
self.objectspace.properties.append(variable.path, 'force_default_on_freeze')
|
||||
variable.hidden = None
|
||||
|
||||
#for idx, value in enumerate(variable.default):
|
||||
# if not hasattr(value, 'name') and not hasattr(value, 'type'):
|
||||
# msg = f'variable "{variable.name}" has a value without text, if you want the value None, set value type to nil'
|
||||
# raise DictConsistencyError(msg, 95, value.xmlfiles)
|
||||
# if not hasattr(value, 'type'):
|
||||
# value.type = variable.type
|
||||
# if hasattr(value, 'name'):
|
||||
# try:
|
||||
# value.name = CONVERT_OPTION.get(value.type, {}).get('func', str)(value.name)
|
||||
# except Exception as err:
|
||||
# msg = _(f'the variable "{variable.name}" has an incorrect value "{value.name}" with "{variable.type}" type')
|
||||
# raise DictConsistencyError(msg, 88, variable.xmlfiles)
|
||||
# else:
|
||||
# value.name = None
|
||||
#if not variable.value:
|
||||
# del variable.value
|
||||
# if variable.type == 'choice':
|
||||
# choice_type = None
|
||||
# if isinstance(variable.choices, Calculation):
|
||||
# self.objectspace.choices.add(variable.path,
|
||||
# variable.choices.to_function(self.functions),
|
||||
# )
|
||||
# else:
|
||||
# for choice in variable.choices:
|
||||
# self.objectspace.choices.append(variable.path,
|
||||
# variable.choices,
|
||||
# )
|
||||
# elif variable.type == 'choice':
|
||||
# msg = _(f'choice is mandatory for the variable "{variable.name}" with choice type')
|
||||
# raise DictConsistencyError(msg, 4, variable.xmlfiles)
|
||||
# variable.doc = variable.description
|
||||
# del variable.description
|
||||
|
||||
def convert_test(self):
|
||||
"""Convert variable tests value
|
||||
|
|
@ -241,17 +233,13 @@ class Annotator(Walk): # pylint: disable=R0903
|
|||
else:
|
||||
value = CONVERT_OPTION.get(variable.type, {}).get('func', str)(value)
|
||||
new_values.append(value)
|
||||
if not hasattr(variable, 'information'):
|
||||
variable.information = self.objectspace.information(variable.xmlfiles)
|
||||
variable.information.test = tuple(new_values)
|
||||
self.objectspace.informations.add(variable.path, 'test', tuple(new_values))
|
||||
|
||||
def convert_help(self):
|
||||
"""Convert variable help
|
||||
"""
|
||||
for variable in self.get_variables():
|
||||
if not hasattr(variable, 'help'):
|
||||
if not hasattr(variable, 'help') or not variable.help:
|
||||
continue
|
||||
if not hasattr(variable, 'information'):
|
||||
variable.information = self.objectspace.information(variable.xmlfiles)
|
||||
variable.information.help = variable.help
|
||||
self.objectspace.informations.add(variable.path, 'help', variable.help)
|
||||
del variable.help
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ DTDDIR = join(dirname(abspath(__file__)), 'data')
|
|||
|
||||
RougailConfig = {'dictionaries_dir': [join(ROUGAILROOT, 'dictionaries')],
|
||||
'extra_dictionaries': {},
|
||||
'services_dir': [join(ROUGAILROOT, 'services')],
|
||||
'patches_dir': join(ROUGAILROOT, 'patches'),
|
||||
'templates_dir': join(ROUGAILROOT, 'templates'),
|
||||
'destinations_dir': join(ROUGAILROOT, 'destinations'),
|
||||
|
|
@ -62,16 +63,17 @@ RougailConfig = {'dictionaries_dir': [join(ROUGAILROOT, 'dictionaries')],
|
|||
'modes_level': ['basic', 'normal', 'expert'],
|
||||
'default_family_mode': 'basic',
|
||||
'default_variable_mode': 'normal',
|
||||
'default_files_engine': 'cheetah',
|
||||
'default_files_engine': 'jinja',
|
||||
'default_files_mode': 644,
|
||||
'default_files_owner': 'root',
|
||||
'default_files_group': 'root',
|
||||
'default_files_included': 'no',
|
||||
'default_overrides_engine': 'cheetah',
|
||||
'default_overrides_engine': 'jinja',
|
||||
'default_service_names_engine': 'none',
|
||||
'default_certificate_domain': 'server_name',
|
||||
'default_certificate_domain': 'rougail.server_name',
|
||||
'base_option_name': 'baseoption',
|
||||
'export_with_import': True,
|
||||
'force_convert_dyn_option_description': False,
|
||||
'suffix': '',
|
||||
'tiramisu_cache': None,
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -92,9 +92,10 @@ def convert_boolean(value: str) -> bool:
|
|||
"""
|
||||
if isinstance(value, bool):
|
||||
return value
|
||||
if value == 'True':
|
||||
value = value.lower()
|
||||
if value == 'true':
|
||||
return True
|
||||
elif value == 'False':
|
||||
elif value == 'false':
|
||||
return False
|
||||
raise Exception(f'unknown boolean value {value}')
|
||||
|
||||
|
|
@ -587,24 +588,24 @@ class RougailObjSpace:
|
|||
getattr(space, child.tag).append(variableobj)
|
||||
else:
|
||||
setattr(space, child.tag, variableobj)
|
||||
|
||||
|
||||
def get_variables(objectspace):
|
||||
"""Iter all variables from the objectspace
|
||||
"""
|
||||
if not hasattr(objectspace.space, 'variables'):
|
||||
return
|
||||
for family in objectspace.space.variables.values():
|
||||
yield from _get_variables(family, objectspace.family)
|
||||
|
||||
|
||||
def _get_variables(family, family_type):
|
||||
if hasattr(family, 'variable'):
|
||||
for variable in family.variable.values():
|
||||
if isinstance(variable, family_type):
|
||||
yield from _get_variables(variable, family_type)
|
||||
else:
|
||||
yield variable
|
||||
if hasattr(family, 'variables'):
|
||||
for family in family.variables.values():
|
||||
yield from _get_variables(family, family_type)
|
||||
#
|
||||
#
|
||||
#def get_variables(objectspace):
|
||||
# """Iter all variables from the objectspace
|
||||
# """
|
||||
# if not hasattr(objectspace.space, 'variables'):
|
||||
# return
|
||||
# for family in objectspace.space.variables.values():
|
||||
# yield from _get_variables(family, objectspace.family)
|
||||
#
|
||||
#
|
||||
#def _get_variables(family, family_type):
|
||||
# if hasattr(family, 'variable'):
|
||||
# for variable in family.variable.values():
|
||||
# if isinstance(variable, family_type):
|
||||
# yield from _get_variables(variable, family_type)
|
||||
# else:
|
||||
# yield variable
|
||||
# if hasattr(family, 'variables'):
|
||||
# for family in family.variables.values():
|
||||
# yield from _get_variables(family, family_type)
|
||||
|
|
|
|||
|
|
@ -16,26 +16,26 @@ You should have received a copy of the GNU General Public License
|
|||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
"""
|
||||
from rougail.objspace import get_variables
|
||||
from rougail.utils import normalize_family
|
||||
|
||||
|
||||
def provider_supplier(objectspace,
|
||||
path_prefix,
|
||||
):
|
||||
n_path_prefix = normalize_family(path_prefix)
|
||||
for variable in get_variables(objectspace):
|
||||
if variable.path_prefix != n_path_prefix:
|
||||
continue
|
||||
if hasattr(variable, 'provider'):
|
||||
family_name, variable.name = variable.path.rsplit('.', 1)
|
||||
objectspace.paths.set_provider(variable,
|
||||
variable.name,
|
||||
family_name,
|
||||
)
|
||||
if hasattr(variable, 'supplier'):
|
||||
family_name, variable.name = variable.path.rsplit('.', 1)
|
||||
objectspace.paths.set_supplier(variable,
|
||||
variable.name,
|
||||
family_name,
|
||||
)
|
||||
#from rougail.objspace import get_variables
|
||||
#from rougail.utils import normalize_family
|
||||
#
|
||||
#
|
||||
#def provider_supplier(objectspace,
|
||||
# path_prefix,
|
||||
# ):
|
||||
# n_path_prefix = normalize_family(path_prefix)
|
||||
# for variable in get_variables(objectspace):
|
||||
# if variable.path_prefix != n_path_prefix:
|
||||
# continue
|
||||
# if hasattr(variable, 'provider'):
|
||||
# family_name, variable.name = variable.path.rsplit('.', 1)
|
||||
# objectspace.paths.set_provider(variable,
|
||||
# variable.name,
|
||||
# family_name,
|
||||
# )
|
||||
# if hasattr(variable, 'supplier'):
|
||||
# family_name, variable.name = variable.path.rsplit('.', 1)
|
||||
# objectspace.paths.set_supplier(variable,
|
||||
# variable.name,
|
||||
# family_name,
|
||||
# )
|
||||
|
|
|
|||
|
|
@ -1,4 +1,20 @@
|
|||
from . import none, cheetah, jinja, creole_legacy
|
||||
|
||||
|
||||
__all__ = ('none', 'cheetah', 'jinja', 'creole_legacy')
|
||||
MODULES = ['none']
|
||||
from . import none
|
||||
try:
|
||||
from . import cheetah
|
||||
MODULES.append('cheetah')
|
||||
except ImportError:
|
||||
pass
|
||||
try:
|
||||
from . import creole_legacy
|
||||
MODULES.append('creole_legacy')
|
||||
except ImportError:
|
||||
pass
|
||||
try:
|
||||
from . import jinja
|
||||
MODULES.append('jinja')
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
__all__ = tuple(MODULES)
|
||||
|
|
|
|||
|
|
@ -35,13 +35,14 @@ from .i18n import _
|
|||
from .annotator import CONVERT_OPTION
|
||||
from .objspace import RootRougailObject
|
||||
from .error import DictConsistencyError
|
||||
from .utils import normalize_family
|
||||
from .utils import normalize_family, Calculation
|
||||
|
||||
|
||||
class BaseElt: # pylint: disable=R0903
|
||||
"""Base element
|
||||
"""
|
||||
path = '.'
|
||||
type = 'family'
|
||||
|
||||
|
||||
def sorted_func_name(func_name):
|
||||
|
|
@ -56,21 +57,28 @@ class TiramisuReflector:
|
|||
def __init__(self,
|
||||
objectspace,
|
||||
funcs_paths,
|
||||
internal_functions,
|
||||
cfg,
|
||||
):
|
||||
self.cfg = cfg
|
||||
self.rougailconfig = objectspace.rougailconfig
|
||||
self.jinja_added = False
|
||||
self.reflector_objects = {}
|
||||
self.text = {'header': [],
|
||||
'option': [],
|
||||
'optiondescription': [],
|
||||
}
|
||||
if self.rougailconfig['export_with_import']:
|
||||
if self.rougailconfig['internal_functions']:
|
||||
for func in self.rougailconfig['internal_functions']:
|
||||
self.text['header'].append(f"func[func] = func")
|
||||
self.text['header'].extend(["from tiramisu import *",
|
||||
"from tiramisu.setting import ALLOWED_LEADER_PROPERTIES",
|
||||
])
|
||||
for mode in self.rougailconfig["modes_level"]:
|
||||
self.text['header'].append(f'ALLOWED_LEADER_PROPERTIES.add("{mode}")')
|
||||
if funcs_paths:
|
||||
if self.cfg['export_with_import']:
|
||||
if self.rougailconfig['export_with_import']:
|
||||
self.text['header'].extend(["from importlib.machinery import SourceFileLoader as _SourceFileLoader",
|
||||
"from importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec",
|
||||
"class func:",
|
||||
" pass",
|
||||
"global func",
|
||||
"func = {'calc_value': calc_value}",
|
||||
"",
|
||||
"def _load_functions(path):",
|
||||
" global _SourceFileLoader, _spec_from_loader, _module_from_spec, func",
|
||||
|
|
@ -81,39 +89,27 @@ class TiramisuReflector:
|
|||
" for function in dir(func_):",
|
||||
" if function.startswith('_'):",
|
||||
" continue",
|
||||
" setattr(func, function, getattr(func_, function))",
|
||||
" func[function] = getattr(func_, function)",
|
||||
])
|
||||
for funcs_path in sorted(funcs_paths, key=sorted_func_name):
|
||||
if not isfile(funcs_path):
|
||||
continue
|
||||
self.text['header'].append(f"_load_functions('{funcs_path}')")
|
||||
if self.cfg['export_with_import']:
|
||||
if internal_functions:
|
||||
for func in internal_functions:
|
||||
self.text['header'].append(f"setattr(func, '{func}', {func})")
|
||||
self.text['header'].extend(["try:",
|
||||
" from tiramisu4 import *",
|
||||
" from tiramisu4.setting import ALLOWED_LEADER_PROPERTIES",
|
||||
"except:",
|
||||
" from tiramisu import *",
|
||||
" from tiramisu.setting import ALLOWED_LEADER_PROPERTIES",
|
||||
])
|
||||
for mode in objectspace.rougailconfig["modes_level"]:
|
||||
self.text['header'].append(f'ALLOWED_LEADER_PROPERTIES.add("{mode}")')
|
||||
self.objectspace = objectspace
|
||||
self.make_tiramisu_objects()
|
||||
if self.cfg['export_with_import'] and (self.cfg['force_convert_dyn_option_description'] or self.objectspace.has_dyn_option is True):
|
||||
if self.rougailconfig['export_with_import'] and (self.rougailconfig['force_convert_dyn_option_description'] or self.objectspace.has_dyn_option is True):
|
||||
self.text['header'].append("from rougail.tiramisu import ConvertDynOptionDescription")
|
||||
for key, value in self.objectspace.jinja.items():
|
||||
self.add_jinja_to_function(key, value)
|
||||
|
||||
def add_jinja_to_function(self,
|
||||
variable_name: str,
|
||||
jinja: str,
|
||||
) -> None:
|
||||
def add_jinja_support(self):
|
||||
if not self.jinja_added:
|
||||
self.text['header'].extend(["from jinja2 import StrictUndefined, DictLoader",
|
||||
"from jinja2.sandbox import SandboxedEnvironment",
|
||||
"from rougail.annotator.variable import CONVERT_OPTION",
|
||||
"from tiramisu.error import ValueWarning",
|
||||
"def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):",
|
||||
" global ENV, CONVERT_OPTION",
|
||||
" kw = {}",
|
||||
" for key, value in kwargs.items():",
|
||||
" if '.' in key:",
|
||||
|
|
@ -124,21 +120,38 @@ class TiramisuReflector:
|
|||
" c_kw[var] = value",
|
||||
" else:",
|
||||
" kw[key] = value",
|
||||
" values = ENV.get_template(__internal_jinja).render(kw)",
|
||||
" values = ENV.get_template(__internal_jinja).render(kw, **func).strip()",
|
||||
" convert = CONVERT_OPTION[__internal_type].get('func', str)",
|
||||
" if __internal_multi:",
|
||||
" return [convert(val) for val in values.split(',')]",
|
||||
" return convert(values)",
|
||||
"def valid_with_jinja(value, **kwargs):",
|
||||
" kwargs[kwargs.pop('__internal_key')] = value",
|
||||
" value = jinja_to_function(__internal_type='string', __internal_multi=False, **kwargs)",
|
||||
" return [convert(val) for val in values.split()]",
|
||||
" values = convert(values)",
|
||||
" return values if values != '' else None",
|
||||
"def variable_to_property(prop, value):",
|
||||
" return prop if value else None",
|
||||
"def jinja_to_property(prop, **kwargs):",
|
||||
" value = func['jinja_to_function'](**kwargs)",
|
||||
" return func['variable_to_property'](prop, value)",
|
||||
"def valid_with_jinja(warning=False, **kwargs):",
|
||||
" global ValueWarning",
|
||||
" value = func['jinja_to_function'](**kwargs)",
|
||||
" if value:",
|
||||
" raise ValueError(value)",
|
||||
"func.jinja_to_function = jinja_to_function",
|
||||
"func.valid_with_jinja = valid_with_jinja",
|
||||
" if warning:",
|
||||
" raise ValueWarning(value)",
|
||||
" else:",
|
||||
" raise ValueError(value)",
|
||||
"func['jinja_to_function'] = jinja_to_function",
|
||||
"func['jinja_to_property'] = jinja_to_property",
|
||||
"func['variable_to_property'] = variable_to_property",
|
||||
"func['valid_with_jinja'] = valid_with_jinja",
|
||||
"dict_env = {}",
|
||||
])
|
||||
self.jinja_added = True
|
||||
|
||||
def add_jinja_to_function(self,
|
||||
variable_name: str,
|
||||
jinja: str,
|
||||
) -> None:
|
||||
self.add_jinja_support()
|
||||
jinja_text = dumps(jinja, ensure_ascii=False)
|
||||
self.text['header'].append(f"dict_env['{variable_name}'] = {jinja_text}")
|
||||
|
||||
|
|
@ -146,20 +159,30 @@ class TiramisuReflector:
|
|||
"""make tiramisu objects
|
||||
"""
|
||||
baseelt = BaseElt()
|
||||
baseelt.reflector_name = f'option_0{self.objectspace.rougailconfig["suffix"]}'
|
||||
self.set_name(baseelt)
|
||||
self.objectspace.reflector_names[baseelt.path] = f'option_0{self.rougailconfig["suffix"]}'
|
||||
basefamily = Family(baseelt,
|
||||
self,
|
||||
)
|
||||
if not self.objectspace.paths.has_path_prefix():
|
||||
for elt in self.reorder_family(self.objectspace.space):
|
||||
self.populate_family(basefamily,
|
||||
elt,
|
||||
)
|
||||
if not hasattr(basefamily.elt, 'information'):
|
||||
basefamily.elt.information = self.objectspace.information(None)
|
||||
basefamily.elt.information = self.objectspace.paths.get_providers_path()
|
||||
basefamily.elt.information.update(self.objectspace.paths.get_suppliers_path())
|
||||
#FIXMEif not self.objectspace.paths.has_path_prefix():
|
||||
if 1:
|
||||
# for elt in self.reorder_family(self.objectspace.space):
|
||||
for elt in self.objectspace.paths.get():
|
||||
if elt.path in self.objectspace.families:
|
||||
Family(elt,
|
||||
self,
|
||||
)
|
||||
else:
|
||||
Variable(elt,
|
||||
self,
|
||||
)
|
||||
|
||||
# self.populate_family(basefamily,
|
||||
# elt,
|
||||
# )
|
||||
#FIXME if not hasattr(basefamily.elt, 'information'):
|
||||
# basefamily.elt.information = self.objectspace.information(None)
|
||||
# basefamily.elt.information = self.objectspace.paths.get_providers_path()
|
||||
# basefamily.elt.information.update(self.objectspace.paths.get_suppliers_path())
|
||||
else:
|
||||
path_prefixes = self.objectspace.paths.get_path_prefixes()
|
||||
for path_prefix in path_prefixes:
|
||||
|
|
@ -179,75 +202,76 @@ class TiramisuReflector:
|
|||
setattr(baseprefix.elt.information, key, value)
|
||||
for key, value in self.objectspace.paths.get_suppliers_path(path_prefix).items():
|
||||
setattr(baseprefix.elt.information, key, value)
|
||||
baseelt.name = normalize_family(self.cfg['base_option_name'])
|
||||
baseelt.doc = self.cfg['base_option_name']
|
||||
baseelt.reflector_object.get([], baseelt.doc, 'base') # pylint: disable=E1101
|
||||
|
||||
def reorder_family(self, space):
|
||||
"""variable_namespace family has to be loaded before any other family
|
||||
because `extra` family could use `variable_namespace` variables.
|
||||
"""
|
||||
if hasattr(space, 'variables'):
|
||||
variable_namespace = self.objectspace.rougailconfig['variable_namespace']
|
||||
if variable_namespace in space.variables:
|
||||
yield space.variables[variable_namespace]
|
||||
for elt, value in space.variables.items():
|
||||
if elt != self.objectspace.rougailconfig['variable_namespace']:
|
||||
yield value
|
||||
if hasattr(space, 'services'):
|
||||
yield space.services
|
||||
|
||||
def populate_family(self,
|
||||
parent_family,
|
||||
elt,
|
||||
):
|
||||
"""Populate family
|
||||
"""
|
||||
self.set_name(elt)
|
||||
family = Family(elt,
|
||||
self,
|
||||
)
|
||||
parent_family.add(family)
|
||||
for children in vars(elt).values():
|
||||
if isinstance(children, self.objectspace.family):
|
||||
self.populate_family(family,
|
||||
children,
|
||||
)
|
||||
continue
|
||||
if isinstance(children, dict):
|
||||
children = list(children.values())
|
||||
if isinstance(children, list):
|
||||
for child in children:
|
||||
if isinstance(child, self.objectspace.property_) or \
|
||||
not isinstance(child, RootRougailObject):
|
||||
continue
|
||||
if isinstance(child, self.objectspace.variable):
|
||||
self.set_name(child)
|
||||
family.add(Variable(child,
|
||||
self,
|
||||
))
|
||||
else:
|
||||
self.populate_family(family,
|
||||
child,
|
||||
)
|
||||
baseelt.name = normalize_family(self.rougailconfig['base_option_name'])
|
||||
baseelt.description = self.rougailconfig['base_option_name']
|
||||
self.reflector_objects[baseelt.path].get([], baseelt.description) # pylint: disable=E1101
|
||||
#
|
||||
# def reorder_family(self, space):
|
||||
# """family has to be loaded before any other family
|
||||
# because `extra` family could use `variable_namespace` variables.
|
||||
# """
|
||||
# if hasattr(space, 'variables'):
|
||||
# variable_namespace = self.rougailconfig['variable_namespace']
|
||||
# if variable_namespace in space.variables:
|
||||
# yield space.variables[variable_namespace]
|
||||
# for elt, value in space.variables.items():
|
||||
# if elt != self.rougailconfig['variable_namespace']:
|
||||
# yield value
|
||||
# if hasattr(space, 'services'):
|
||||
# yield space.services
|
||||
#
|
||||
# def populate_family(self,
|
||||
# parent_family,
|
||||
# elt,
|
||||
# ):
|
||||
# """Populate family
|
||||
# """
|
||||
# self.set_name(elt)
|
||||
# family = Family(elt,
|
||||
# self,
|
||||
# )
|
||||
# parent_family.add(family)
|
||||
# for children in vars(elt).values():
|
||||
# if isinstance(children, self.objectspace.family):
|
||||
# self.populate_family(family,
|
||||
# children,
|
||||
# )
|
||||
# continue
|
||||
# if isinstance(children, dict):
|
||||
# children = list(children.values())
|
||||
# if isinstance(children, list):
|
||||
# for child in children:
|
||||
# if isinstance(child, self.objectspace.property_) or \
|
||||
# not isinstance(child, RootRougailObject):
|
||||
# continue
|
||||
# if isinstance(child, self.objectspace.variable):
|
||||
# self.set_name(child)
|
||||
# family.add(Variable(child,
|
||||
# self,
|
||||
# ))
|
||||
# else:
|
||||
# self.populate_family(family,
|
||||
# child,
|
||||
# )
|
||||
|
||||
def set_name(self,
|
||||
elt,
|
||||
):
|
||||
"""Set name
|
||||
"""
|
||||
if not hasattr(elt, 'reflector_name'):
|
||||
self.objectspace.paths.set_name(elt, 'optiondescription_')
|
||||
return elt.reflector_name
|
||||
if elt.path not in self.objectspace.reflector_names:
|
||||
self.objectspace.set_name(elt, 'optiondescription_')
|
||||
return self.objectspace.reflector_names[elt.path]
|
||||
|
||||
def get_text(self):
|
||||
"""Get text
|
||||
"""
|
||||
if self.jinja_added:
|
||||
self.text['header'].extend(["ENV = SandboxedEnvironment(loader=DictLoader(dict_env), undefined=StrictUndefined)",
|
||||
"ENV.filters = func",
|
||||
"ENV.compile_templates('jinja_caches', zip=None)",
|
||||
])
|
||||
return '\n'.join(self.text['header'] + self.text['option'] + self.text['optiondescription'])
|
||||
return '\n'.join(self.text['header'] + self.text['option'])
|
||||
|
||||
|
||||
class Common:
|
||||
|
|
@ -257,13 +281,14 @@ class Common:
|
|||
elt,
|
||||
tiramisu,
|
||||
):
|
||||
self.objectspace = tiramisu.objectspace
|
||||
self.elt = elt
|
||||
self.option_name = None
|
||||
self.tiramisu = tiramisu
|
||||
self.elt.reflector_object = self
|
||||
tiramisu.reflector_objects[elt.path] = self
|
||||
self.object_type = None
|
||||
|
||||
def get(self, calls, parent_name, typ):
|
||||
def get(self, calls, parent_name):
|
||||
"""Get tiramisu's object
|
||||
"""
|
||||
self_calls = calls.copy()
|
||||
|
|
@ -273,7 +298,7 @@ class Common:
|
|||
self_calls.append(self.elt.path)
|
||||
self.calls = self_calls
|
||||
if self.option_name is None:
|
||||
self.option_name = self.elt.reflector_name
|
||||
self.option_name = self.objectspace.reflector_names[self.elt.path]
|
||||
self.populate_attrib()
|
||||
self.populate_informations()
|
||||
return self.option_name
|
||||
|
|
@ -282,19 +307,13 @@ class Common:
|
|||
"""Populate attributes
|
||||
"""
|
||||
keys = {'name': self.convert_str(self.elt.name)}
|
||||
if hasattr(self.elt, 'doc'):
|
||||
keys['doc'] = self.convert_str(self.elt.doc)
|
||||
if hasattr(self.elt, 'description') and self.elt.description:
|
||||
keys['doc'] = self.convert_str(self.elt.description)
|
||||
self._populate_attrib(keys)
|
||||
if hasattr(self.elt, 'properties'):
|
||||
keys['properties'] = self.properties_to_string(self.elt.properties)
|
||||
if self.elt.path in self.objectspace.properties:
|
||||
keys['properties'] = self.properties_to_string(self.objectspace.properties[self.elt.path])
|
||||
attrib = ', '.join([f'{key}={value}' for key, value in keys.items()])
|
||||
if self.__class__.__name__ == 'Family':
|
||||
#pouet
|
||||
name = 'option'
|
||||
#name = 'optiondescription'
|
||||
else:
|
||||
name = 'option'
|
||||
self.tiramisu.text[name].append(f'{self.option_name} = {self.object_type}({attrib})')
|
||||
self.tiramisu.text['option'].append(f'{self.option_name} = {self.object_type}({attrib})')
|
||||
|
||||
def _populate_attrib(self,
|
||||
keys: dict,
|
||||
|
|
@ -312,37 +331,37 @@ class Common:
|
|||
) -> None:
|
||||
"""Change properties to string
|
||||
"""
|
||||
properties = [self.convert_str(property_) for property_ in values
|
||||
if isinstance(property_, str)]
|
||||
calc_properties = [self.calc_properties(property_) for property_ in values \
|
||||
if isinstance(property_, self.tiramisu.objectspace.property_)]
|
||||
properties = []
|
||||
calc_properties = []
|
||||
for property_, value in values.items():
|
||||
if value is True:
|
||||
properties.append(self.convert_str(property_))
|
||||
else:
|
||||
calc_properties.append(self.calculation_value('property', value))
|
||||
return 'frozenset({' + ', '.join(sorted(properties) + calc_properties) + '})'
|
||||
|
||||
def calc_properties(self,
|
||||
child,
|
||||
prop,
|
||||
calculation,
|
||||
) -> str:
|
||||
"""Populate properties
|
||||
"""
|
||||
option_name = child.source.reflector_object.get(self.calls, self.elt.path, 'property')
|
||||
pouet
|
||||
option_name = self.tiramisu.reflector_objects[child.source.path].get(self.calls, self.elt.path)
|
||||
kwargs = (f"'condition': ParamOption({option_name}, notraisepropertyerror=True), "
|
||||
f"'expected': {self.populate_param(child.expected)}")
|
||||
if child.inverse:
|
||||
kwargs += ", 'reverse_condition': ParamValue(True)"
|
||||
return (f"Calculation(func.calc_value, Params(ParamValue('{child.name}'), "
|
||||
f"kwargs={{{kwargs}}}), func.calc_value_property_help)")
|
||||
return (f"Calculation(func['calc_value'], Params(ParamValue('{child.name}'), "
|
||||
f"kwargs={{{kwargs}}}), func['calc_value_property_help'])")
|
||||
|
||||
def populate_informations(self):
|
||||
"""Populate Tiramisu's informations
|
||||
"""
|
||||
if not hasattr(self.elt, 'information'):
|
||||
informations = self.objectspace.informations.get(self.elt.path)
|
||||
if not informations:
|
||||
return
|
||||
if isinstance(self.elt.information, dict):
|
||||
informations = self.elt.information
|
||||
else:
|
||||
informations = vars(self.elt.information)
|
||||
for key, value in informations.items():
|
||||
if key == 'xmlfiles':
|
||||
continue
|
||||
if isinstance(value, str):
|
||||
value = self.convert_str(value)
|
||||
self.tiramisu.text['option'].append(f"{self.option_name}.impl_set_information('{key}', {value})")
|
||||
|
|
@ -352,51 +371,55 @@ class Common:
|
|||
):
|
||||
"""Populate variable parameters
|
||||
"""
|
||||
if param.type in ['number', 'boolean', 'nil', 'port', 'choice', 'space']:
|
||||
return f'ParamValue({param.text})'
|
||||
if param.type in ['variable_name', 'variable']:
|
||||
if isinstance(param, self.objectspace.variable):
|
||||
return self.build_option_param(param)
|
||||
if param.type == 'information':
|
||||
if hasattr(self.elt, 'multi') and self.elt.multi:
|
||||
if not isinstance(param, dict):
|
||||
if isinstance(param, str):
|
||||
value = self.convert_str(param)
|
||||
else:
|
||||
value = param
|
||||
return f'ParamValue({value})'
|
||||
if param['type'] == 'information':
|
||||
if self.elt.multi:
|
||||
default = []
|
||||
else:
|
||||
default = None
|
||||
if hasattr(param, 'variable'):
|
||||
if param.variable.path == self.elt.path:
|
||||
return f'ParamSelfInformation("{param.text}", {default})'
|
||||
return f'ParamInformation("{param.text}", {default}, option={param.variable.reflector_object.get(self.calls, self.elt.path, "param")})'
|
||||
return f'ParamInformation("{param.text}", {default})'
|
||||
if param.type == 'suffix':
|
||||
return f'ParamSelfInformation("{param["information"]}", {default})'
|
||||
return f'ParamInformation("{param["information"]}", {default}, option={self.tiramisu.reflector_objects[param["variable"].path].get(self.calls, self.elt.path)})'
|
||||
return f'ParamInformation("{param["information"]}", {default})'
|
||||
if param['type'] == 'suffix':
|
||||
return 'ParamSuffix()'
|
||||
if param.type == 'index':
|
||||
if param['type'] == 'index':
|
||||
return 'ParamIndex()'
|
||||
if param.type == 'jinja':
|
||||
self.tiramisu.add_jinja_to_function(self.elt.path, param.text)
|
||||
return f'ParamValue("{self.elt.path}")'
|
||||
value = self.convert_str(param.text)
|
||||
return f'ParamValue({value})'
|
||||
if param['type'] == 'variable':
|
||||
return self.build_option_param(param['variable'],
|
||||
param.get('propertyerror', True),
|
||||
)
|
||||
raise Exception('pfff')
|
||||
|
||||
def build_option_param(self,
|
||||
param,
|
||||
propertyerror=True,
|
||||
) -> str:
|
||||
"""build variable parameters
|
||||
"""
|
||||
if param.type == 'variable':
|
||||
option_name = param.text.reflector_object.get(self.calls, self.elt.path, 'param')
|
||||
else:
|
||||
option_name = param.text
|
||||
if param.path == self.elt.path:
|
||||
return 'ParamSelfOption(whole=False)'
|
||||
option_name = self.tiramisu.reflector_objects[param.path].get(self.calls, self.elt.path)
|
||||
params = [f'{option_name}']
|
||||
if hasattr(param, 'suffix'):
|
||||
param_type = 'ParamDynOption'
|
||||
family = param.family.reflector_object.get(self.calls, self.elt.path, 'suffix')
|
||||
family = self.tiramisu.reflector_objects[param.family.path].get(self.calls, self.elt.path)
|
||||
params.extend([f"'{param.suffix}'", f'{family}'])
|
||||
if param.optional:
|
||||
params.append('optional=True')
|
||||
else:
|
||||
param_type = 'ParamOption'
|
||||
if not param.propertyerror:
|
||||
if not propertyerror:
|
||||
params.append('notraisepropertyerror=True')
|
||||
return "{}({})".format(param_type, ', '.join(params))
|
||||
return f'{param_type}({", ".join(params)})'
|
||||
|
||||
|
||||
class Variable(Common):
|
||||
|
|
@ -412,30 +435,50 @@ class Variable(Common):
|
|||
def _populate_attrib(self,
|
||||
keys: dict,
|
||||
):
|
||||
if hasattr(self.elt, 'opt'):
|
||||
keys['opt'] = self.elt.opt.reflector_object.get(self.calls, self.elt.path, 'opt')
|
||||
if hasattr(self.elt, 'choice'):
|
||||
values = self.elt.choice
|
||||
if values[0].type == 'variable':
|
||||
value = values[0].name.reflector_object.get(self.calls, self.elt.path, 'choice')
|
||||
keys['values'] = f"Calculation(func.calc_value, Params((ParamOption({value}))))"
|
||||
elif values[0].type == 'function':
|
||||
keys['values'] = self.calculation_value(values[0], [])
|
||||
if self.elt.type == 'symlink':
|
||||
keys['opt'] = self.tiramisu.reflector_objects[self.elt.opt.path].get(self.calls, self.elt.path)
|
||||
if self.elt.type == 'choice':
|
||||
values = self.elt.choices
|
||||
if isinstance(values, Calculation):
|
||||
keys['values'] = self.calculation_value('choice', values)
|
||||
# if values['type'] == 'variable':
|
||||
# value = self.tiramisu.reflector_objects[values['variable'].path].get(self.calls, self.elt.path)
|
||||
# keys['values'] = f"Calculation(func['calc_value'], Params((ParamOption({value}))))"
|
||||
# elif values['type'] == 'jinja':
|
||||
# keys['values'] = self.calculation_value(values)
|
||||
else:
|
||||
keys['values'] = str(tuple([val.name for val in values]))
|
||||
if hasattr(self.elt, 'multi') and self.elt.multi:
|
||||
keys['multi'] = self.elt.multi
|
||||
for key in ['default', 'default_multi']:
|
||||
if hasattr(self.elt, key) and getattr(self.elt, key) is not None:
|
||||
value = getattr(self.elt, key)
|
||||
if isinstance(value, str):
|
||||
value = self.convert_str(value)
|
||||
elif isinstance(value, self.tiramisu.objectspace.value):
|
||||
value = self.calculation_value(value, [], calc_multi=value.calc_multi)
|
||||
keys[key] = value
|
||||
if hasattr(self.elt, 'validators'):
|
||||
keys['validators'] = '[' + ', '.join([self.calculation_value(val,
|
||||
['ParamSelfOption(whole=False)']) for val in self.elt.validators]) + ']'
|
||||
new_values = []
|
||||
for value in values:
|
||||
if isinstance(value, Calculation):
|
||||
new_values.append(self.calculation_value('choice', value))
|
||||
else:
|
||||
new_values.append(value)
|
||||
keys['values'] = tuple(new_values)
|
||||
if self.elt.path in self.objectspace.multis:
|
||||
keys['multi'] = self.objectspace.multis[self.elt.path]
|
||||
if hasattr(self.elt, 'default') and self.elt.default is not None:
|
||||
value = self.elt.default
|
||||
if isinstance(value, str):
|
||||
value = self.convert_str(value)
|
||||
elif isinstance(value, Calculation):
|
||||
value = self.calculation_value('default', value)
|
||||
keys['default'] = value
|
||||
if self.elt.path in self.objectspace.default_multi:
|
||||
value = self.objectspace.default_multi[self.elt.path]
|
||||
if isinstance(value, str):
|
||||
value = self.convert_str(value)
|
||||
elif isinstance(value, Calculation):
|
||||
value = self.calculation_value('default_multi', value) # calc_multi=key == 'calc_multi')
|
||||
keys['default_multi'] = value
|
||||
if self.elt.validators:
|
||||
validators = []
|
||||
for val in self.elt.validators:
|
||||
if isinstance(val, Calculation):
|
||||
validators.append(self.calculation_value('validator', val))
|
||||
else:
|
||||
validators.append(val)
|
||||
keys['validators'] = '[' + ', '.join(validators) + ']'
|
||||
#keys['validators'] = '[' + ', '.join([self.calculation_value(val)['ParamSelfOption(whole=False)']) for val in self.elt.validators]) + ']'
|
||||
for key in ['min_number', 'max_number']:
|
||||
if hasattr(self.elt, key):
|
||||
keys[key] = getattr(self.elt, key)
|
||||
|
|
@ -445,37 +488,39 @@ class Variable(Common):
|
|||
keys[key] = value
|
||||
|
||||
def calculation_value(self,
|
||||
child,
|
||||
args,
|
||||
calc_multi=False,
|
||||
typ: str,
|
||||
function,
|
||||
# function,
|
||||
) -> str:
|
||||
"""Generate calculated value
|
||||
"""
|
||||
kwargs = []
|
||||
# has parameters
|
||||
function = child.name
|
||||
new_args = []
|
||||
if hasattr(child, 'param'):
|
||||
for param in child.param:
|
||||
value = self.populate_param(param)
|
||||
if not hasattr(param, 'name'):
|
||||
new_args.append(str(value))
|
||||
else:
|
||||
kwargs.append(f"'{param.name}': " + value)
|
||||
if function == 'valid_network_netmask':
|
||||
new_args.extend(args)
|
||||
self.tiramisu.add_jinja_support()
|
||||
if typ == 'property':
|
||||
child = function.to_property_function()
|
||||
elif typ == 'default':
|
||||
child = function.to_default_function()
|
||||
elif typ == 'validator':
|
||||
child = function.to_validator_function()
|
||||
elif typ == 'choice':
|
||||
child = function.to_choice_function()
|
||||
else:
|
||||
args.extend(new_args)
|
||||
new_args = args
|
||||
ret = f'Calculation(func.{function}, Params((' + ', '.join(new_args) + ')'
|
||||
raise Exception('connard')
|
||||
new_args = []
|
||||
kwargs = []
|
||||
if 'params' in child:
|
||||
for key, value in child['params'].items():
|
||||
if not key:
|
||||
for val in value:
|
||||
new_args.append(self.populate_param(val))
|
||||
else:
|
||||
kwargs.append(f"'{key}': " + self.populate_param(value))
|
||||
ret = f"Calculation(func['{child['function']}'], Params((" + ', '.join(new_args) + ')'
|
||||
if kwargs:
|
||||
ret += ', kwargs={' + ', '.join(kwargs) + '}'
|
||||
ret += ')'
|
||||
if hasattr(child, 'warnings_only'):
|
||||
ret += f', warnings_only={child.warnings_only}'
|
||||
ret = ret + ')'
|
||||
if calc_multi:
|
||||
ret = '[' + ret + ']'
|
||||
return ret
|
||||
|
||||
|
||||
|
|
@ -487,10 +532,10 @@ class Family(Common):
|
|||
tiramisu,
|
||||
):
|
||||
super().__init__(elt, tiramisu)
|
||||
if hasattr(self.elt, 'suffixes'):
|
||||
if self.elt.type == 'dynamic':
|
||||
self.tiramisu.objectspace.has_dyn_option = True
|
||||
self.object_type = 'ConvertDynOptionDescription'
|
||||
elif hasattr(self.elt, 'leadership') and self.elt.leadership:
|
||||
elif self.elt.type == 'leadership':
|
||||
self.object_type = 'Leadership'
|
||||
else:
|
||||
self.object_type = 'OptionDescription'
|
||||
|
|
@ -504,7 +549,10 @@ class Family(Common):
|
|||
def _populate_attrib(self,
|
||||
keys: list,
|
||||
) -> None:
|
||||
if hasattr(self.elt, 'suffixes'):
|
||||
dyn = self.elt.suffixes.reflector_object.get(self.calls, self.elt.path, 'suffixes')
|
||||
keys['suffixes'] = f"Calculation(func.calc_value, Params((ParamOption({dyn}, notraisepropertyerror=True))))"
|
||||
keys['children'] = '[' + ', '.join([child.get(self.calls, self.elt.path, 'child') for child in self.children]) + ']'
|
||||
if self.elt.type == 'dynamic':
|
||||
dyn = self.tiramisu.reflector_objects[self.elt.variable.path].get(self.calls, self.elt.path)
|
||||
keys['suffixes'] = f"Calculation(func['calc_value'], Params((ParamOption({dyn}, notraisepropertyerror=True))))"
|
||||
children = []
|
||||
for path in self.objectspace.parents[self.elt.path]:
|
||||
children.append(self.objectspace.paths[path])
|
||||
keys['children'] = '[' + ', '.join([self.tiramisu.reflector_objects[child.path].get(self.calls, self.elt.path) for child in children]) + ']'
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -27,13 +27,17 @@ You should have received a copy of the GNU General Public License
|
|||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
"""
|
||||
from typing import List
|
||||
from typing import List, Union
|
||||
from unicodedata import normalize, combining
|
||||
import re
|
||||
|
||||
from importlib.machinery import SourceFileLoader
|
||||
from importlib.util import spec_from_loader, module_from_spec
|
||||
|
||||
from jinja2 import Undefined, UndefinedError, DictLoader
|
||||
from jinja2.sandbox import SandboxedEnvironment
|
||||
from jinja2.utils import missing
|
||||
|
||||
from .i18n import _
|
||||
from .error import DictConsistencyError
|
||||
|
||||
|
|
@ -69,3 +73,221 @@ def load_modules(eosfunc_file) -> List[str]:
|
|||
eosfunc = module_from_spec(spec)
|
||||
loader.exec_module(eosfunc)
|
||||
return eosfunc
|
||||
|
||||
|
||||
class CollectUndefined(Undefined):
|
||||
def __init__(self,
|
||||
hint=None,
|
||||
obj=missing,
|
||||
name=None,
|
||||
exc=UndefinedError,
|
||||
subname=None,
|
||||
) -> None:
|
||||
self._undefined_hint = hint
|
||||
self._undefined_obj = obj
|
||||
self._undefined_name = name
|
||||
self._undefined_exception = exc
|
||||
if subname:
|
||||
full_name = subname + '.'
|
||||
else:
|
||||
full_name = ''
|
||||
full_name += self._undefined_name
|
||||
self.variables.add(full_name)
|
||||
self._undefined_full_name = full_name
|
||||
|
||||
def __getattr__(self, name):
|
||||
return CollectUndefined(name=name, subname=self._undefined_full_name)
|
||||
|
||||
|
||||
def get_jinja_variable_to_param(jinja_text,
|
||||
objectspace,
|
||||
xmlfiles,
|
||||
path_prefix,
|
||||
functions,
|
||||
variable_name,
|
||||
variable_path,
|
||||
):
|
||||
CollectUndefined.variables = set()
|
||||
try:
|
||||
env = SandboxedEnvironment(loader=DictLoader({'tmpl': jinja_text}),
|
||||
undefined=CollectUndefined,
|
||||
)
|
||||
#add functions as filters
|
||||
env.filters = functions
|
||||
# and functions
|
||||
env.get_template('tmpl').render(**functions)
|
||||
except UndefinedError as err:
|
||||
msg = _(f'error in jinja "{jinja_text}": {err}')
|
||||
raise DictConsistencyError(msg, 91, xmlfiles) from err
|
||||
variables = list(CollectUndefined.variables)
|
||||
variables.sort()
|
||||
for variable in variables:
|
||||
if variable in ['__suffix', '__index']:
|
||||
yield variable
|
||||
if variable in objectspace.variables:
|
||||
yield objectspace.paths[variable]
|
||||
|
||||
|
||||
class Calculation:
|
||||
def __init__(self,
|
||||
object_name: str,
|
||||
attribute: str,
|
||||
path: str,
|
||||
datas: Union[dict, List[dict]],
|
||||
filename: str,
|
||||
objectspace: 'RougailConvert',
|
||||
inside_list: bool,
|
||||
) -> None:
|
||||
if 'type' not in datas:
|
||||
raise Exception(f'the {object_name} "{path}" in "{filename}" must have a "type" attribut for "{attribute}"')
|
||||
self.type = datas.pop('type')
|
||||
self.path = path
|
||||
self.attribute = attribute
|
||||
if self.type != 'suffix':
|
||||
self.value = datas.pop(self.type)
|
||||
if 'params' in datas:
|
||||
if self.type == 'variable':
|
||||
raise Exception('param not allowed with type variable')
|
||||
self.params = datas.pop('params')
|
||||
for key, value in self.params.items():
|
||||
if isinstance(value, dict) and value['type'] == 'variable':
|
||||
variable, suffix = objectspace.paths.get_with_dynamic(value['variable'])
|
||||
if variable:
|
||||
if not isinstance(variable, objectspace.variable):
|
||||
print("pfff it's a family")
|
||||
self.params[key]['variable'] = variable
|
||||
if suffix:
|
||||
self.params[key]['suffix'] = suffix
|
||||
else:
|
||||
if not value.get('optional'):
|
||||
raise Exception('pffff')
|
||||
self.params[key] = None
|
||||
else:
|
||||
self.params = {}
|
||||
if 'return_type' in datas:
|
||||
self.return_type = datas.pop('return_type')
|
||||
if self.return_type not in objectspace.variable_types:
|
||||
raise Exception(f'unknown "return_type" in {attribute} of variable "{self.path}"')
|
||||
else:
|
||||
self.return_type = None
|
||||
if datas:
|
||||
raise Exception('hu.?')
|
||||
self.objectspace = objectspace
|
||||
self.inside_list = inside_list
|
||||
|
||||
def _jinja_to_function(self,
|
||||
function,
|
||||
return_type,
|
||||
multi,
|
||||
):
|
||||
# FIXME
|
||||
path_prefix = None
|
||||
variable = self.objectspace.paths[self.path]
|
||||
jinja_path = f'{self.attribute}_{self.path}'
|
||||
idx = 0
|
||||
while jinja_path in self.objectspace.jinja:
|
||||
jinja_path = f'{self.attribute}_{self.path}_{idx}'
|
||||
idx += 1
|
||||
self.objectspace.jinja[jinja_path] = self.value
|
||||
default = {'function': function,
|
||||
'params': {'__internal_jinja': jinja_path,
|
||||
'__internal_type': return_type,
|
||||
'__internal_multi': multi,
|
||||
}
|
||||
}
|
||||
if self.params:
|
||||
default['params'] |= self.params
|
||||
for sub_variable in get_jinja_variable_to_param(self.value,
|
||||
self.objectspace,
|
||||
variable.xmlfiles,
|
||||
path_prefix,
|
||||
self.objectspace.functions,
|
||||
None,
|
||||
None,
|
||||
):
|
||||
if isinstance(sub_variable, self.objectspace.variable):
|
||||
default['params'][sub_variable.path] = sub_variable
|
||||
return default
|
||||
|
||||
def to_property_function(self) -> dict:
|
||||
if self.return_type:
|
||||
raise Exception('return_type not allowed!')
|
||||
if self.type == 'jinja':
|
||||
if None in self.params:
|
||||
self.params[None] = [self.attribute] + self.params[None]
|
||||
else:
|
||||
self.params[None] = [self.attribute]
|
||||
return self._jinja_to_function('jinja_to_property',
|
||||
'boolean',
|
||||
False,
|
||||
)
|
||||
if self.type == 'variable':
|
||||
variable = self.objectspace.paths[self.value]
|
||||
if variable.type != 'boolean':
|
||||
raise Exception('only boolean!')
|
||||
default = {'function': 'variable_to_property',
|
||||
'params': {None: [self.attribute, variable]}
|
||||
}
|
||||
return default
|
||||
raise Exception('pfff')
|
||||
|
||||
def to_default_function(self) -> dict:
|
||||
if self.type == 'jinja':
|
||||
if self.return_type:
|
||||
return_type = self.return_type
|
||||
else:
|
||||
variable = self.objectspace.paths[self.path]
|
||||
return_type = variable.type
|
||||
if self.inside_list:
|
||||
multi = False
|
||||
else:
|
||||
multi = self.path in self.objectspace.multis
|
||||
return self._jinja_to_function('jinja_to_function',
|
||||
return_type,
|
||||
multi,
|
||||
)
|
||||
elif self.type == 'variable':
|
||||
return {'function': 'calc_value',
|
||||
'params': {None: [self.objectspace.paths[self.value]],
|
||||
'multi': self.path in self.objectspace.multis,
|
||||
'allow_none': True,
|
||||
}
|
||||
}
|
||||
elif self.type == 'suffix':
|
||||
if self.params:
|
||||
raise Exception('pfff')
|
||||
return {'function': 'calc_value',
|
||||
'params': {None: [{'type': 'suffix'}],
|
||||
'multi': self.objectspace.paths[self.path].multi,
|
||||
}
|
||||
}
|
||||
else:
|
||||
raise Exception('pfff')
|
||||
|
||||
def to_validator_function(self) -> dict:
|
||||
if self.type == 'jinja':
|
||||
return self._jinja_to_function('valid_with_jinja',
|
||||
'string',
|
||||
False,
|
||||
)
|
||||
else:
|
||||
raise Exception('pfff')
|
||||
|
||||
def to_choice_function(self) -> dict:
|
||||
if self.type == 'jinja':
|
||||
return self._jinja_to_function('jinja_to_function',
|
||||
self.return_type,
|
||||
not self.inside_list,
|
||||
)
|
||||
elif self.type == 'variable':
|
||||
variable = self.objectspace.paths[self.value]
|
||||
if self.path in self.objectspace.multis is self.inside_list:
|
||||
raise Exception('pffff')
|
||||
return {'function': 'calc_value',
|
||||
'params': {None: [self.objectspace.paths[self.value]],
|
||||
'multi': True,
|
||||
'allow_none': True,
|
||||
}
|
||||
}
|
||||
else:
|
||||
raise Exception('pfff')
|
||||
|
|
|
|||
|
|
@ -1,7 +1,12 @@
|
|||
from tiramisu import *
|
||||
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||
ALLOWED_LEADER_PROPERTIES.add("normal")
|
||||
ALLOWED_LEADER_PROPERTIES.add("expert")
|
||||
from importlib.machinery import SourceFileLoader as _SourceFileLoader
|
||||
from importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec
|
||||
class func:
|
||||
pass
|
||||
global func
|
||||
func = {'calc_value': calc_value}
|
||||
|
||||
def _load_functions(path):
|
||||
global _SourceFileLoader, _spec_from_loader, _module_from_spec, func
|
||||
|
|
@ -12,20 +17,6 @@ def _load_functions(path):
|
|||
for function in dir(func_):
|
||||
if function.startswith('_'):
|
||||
continue
|
||||
setattr(func, function, getattr(func_, function))
|
||||
func[function] = getattr(func_, function)
|
||||
_load_functions('tests/dictionaries/../eosfunc/test.py')
|
||||
try:
|
||||
from tiramisu4 import *
|
||||
from tiramisu4.setting import ALLOWED_LEADER_PROPERTIES
|
||||
except:
|
||||
from tiramisu import *
|
||||
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||
ALLOWED_LEADER_PROPERTIES.add("normal")
|
||||
ALLOWED_LEADER_PROPERTIES.add("expert")
|
||||
option_1 = BoolOption(name="activate", doc="activate", default=True)
|
||||
option_2 = BoolOption(name="manage", doc="manage", default=True)
|
||||
optiondescription_4 = OptionDescription(name="tata_service", doc="tata.service", children=[option_1, option_2])
|
||||
optiondescription_4.impl_set_information('type', "service")
|
||||
optiondescription_3 = OptionDescription(name="services", doc="services", children=[optiondescription_4], properties=frozenset({"hidden"}))
|
||||
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_3])
|
||||
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[])
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
version: '1.0'
|
||||
my_family:
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version: '1.0'
|
||||
my_family:
|
||||
my_sub_family:
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"rougail.myvar": {
|
||||
"owner": "forced",
|
||||
"value": "no"
|
||||
},
|
||||
"rougail.server_deployed": {
|
||||
"owner": "default",
|
||||
"value": false
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"rougail.myvar": "no",
|
||||
"rougail.server_deployed": false
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"rougail.myvar": {
|
||||
"owner": "default",
|
||||
"value": "no"
|
||||
},
|
||||
"rougail.server_deployed": {
|
||||
"owner": "default",
|
||||
"value": false
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
from importlib.machinery import SourceFileLoader as _SourceFileLoader
|
||||
from importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec
|
||||
class func:
|
||||
pass
|
||||
|
||||
def _load_functions(path):
|
||||
global _SourceFileLoader, _spec_from_loader, _module_from_spec, func
|
||||
loader = _SourceFileLoader('func', path)
|
||||
spec = _spec_from_loader(loader.name, loader)
|
||||
func_ = _module_from_spec(spec)
|
||||
loader.exec_module(func_)
|
||||
for function in dir(func_):
|
||||
if function.startswith('_'):
|
||||
continue
|
||||
setattr(func, function, getattr(func_, function))
|
||||
_load_functions('tests/dictionaries/../eosfunc/test.py')
|
||||
try:
|
||||
from tiramisu4 import *
|
||||
from tiramisu4.setting import ALLOWED_LEADER_PROPERTIES
|
||||
except:
|
||||
from tiramisu import *
|
||||
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||
ALLOWED_LEADER_PROPERTIES.add("normal")
|
||||
ALLOWED_LEADER_PROPERTIES.add("expert")
|
||||
option_2 = BoolOption(name="server_deployed", doc="server_deployed", default=False, properties=frozenset({"mandatory", "normal"}))
|
||||
option_1 = StrOption(name="myvar", doc="myvar", default="no", properties=frozenset({"basic", "force_store_value", "mandatory", Calculation(func.calc_value, Params(ParamValue('frozen'), kwargs={'condition': ParamOption(option_2, notraisepropertyerror=True), 'expected': ParamValue(True)}), func.calc_value_property_help)}))
|
||||
optiondescription_3 = OptionDescription(name="rougail", doc="Rougail", children=[option_1, option_2], properties=frozenset({"basic"}))
|
||||
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_3])
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
from importlib.machinery import SourceFileLoader as _SourceFileLoader
|
||||
from importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec
|
||||
class func:
|
||||
pass
|
||||
|
||||
def _load_functions(path):
|
||||
global _SourceFileLoader, _spec_from_loader, _module_from_spec, func
|
||||
loader = _SourceFileLoader('func', path)
|
||||
spec = _spec_from_loader(loader.name, loader)
|
||||
func_ = _module_from_spec(spec)
|
||||
loader.exec_module(func_)
|
||||
for function in dir(func_):
|
||||
if function.startswith('_'):
|
||||
continue
|
||||
setattr(func, function, getattr(func_, function))
|
||||
_load_functions('tests/dictionaries/../eosfunc/test.py')
|
||||
try:
|
||||
from tiramisu4 import *
|
||||
from tiramisu4.setting import ALLOWED_LEADER_PROPERTIES
|
||||
except:
|
||||
from tiramisu import *
|
||||
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||
ALLOWED_LEADER_PROPERTIES.add("normal")
|
||||
ALLOWED_LEADER_PROPERTIES.add("expert")
|
||||
option_2 = BoolOption(name="server_deployed", doc="server_deployed", default=False, properties=frozenset({"mandatory", "normal"}))
|
||||
option_1 = StrOption(name="myvar", doc="myvar", default="no", properties=frozenset({"basic", "force_store_value", "mandatory", Calculation(func.calc_value, Params(ParamValue('frozen'), kwargs={'condition': ParamOption(option_2, notraisepropertyerror=True), 'expected': ParamValue(True)}), func.calc_value_property_help)}))
|
||||
optiondescription_6 = OptionDescription(name="rougail", doc="Rougail", children=[option_1, option_2], properties=frozenset({"basic"}))
|
||||
optiondescription_5 = OptionDescription(name="1", doc="1", children=[optiondescription_6])
|
||||
option_4 = BoolOption(name="server_deployed", doc="server_deployed", default=False, properties=frozenset({"mandatory", "normal"}))
|
||||
option_3 = StrOption(name="myvar", doc="myvar", default="no", properties=frozenset({"basic", "force_store_value", "mandatory", Calculation(func.calc_value, Params(ParamValue('frozen'), kwargs={'condition': ParamOption(option_4, notraisepropertyerror=True), 'expected': ParamValue(True)}), func.calc_value_property_help)}))
|
||||
optiondescription_8 = OptionDescription(name="rougail", doc="Rougail", children=[option_3, option_4], properties=frozenset({"basic"}))
|
||||
optiondescription_7 = OptionDescription(name="2", doc="2", children=[optiondescription_8])
|
||||
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_5, optiondescription_7])
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<rougail version="0.10">
|
||||
<variables>
|
||||
<variable name="myvar" auto_freeze="True">
|
||||
<value>no</value>
|
||||
</variable>
|
||||
<variable name="server_deployed" type="boolean">
|
||||
<value>False</value>
|
||||
</variable>
|
||||
</variables>
|
||||
</rougail>
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
version: '0.10'
|
||||
variables:
|
||||
- variable:
|
||||
- name: myvar
|
||||
auto_freeze: true
|
||||
value:
|
||||
- text: 'no'
|
||||
- name: server_deployed
|
||||
type: boolean
|
||||
value:
|
||||
- text: false
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"rougail.my_var": {
|
||||
"owner": "forced",
|
||||
"value": "no"
|
||||
},
|
||||
"rougail.server_deployed": {
|
||||
"owner": "default",
|
||||
"value": false
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"rougail.my_var": "no",
|
||||
"rougail.server_deployed": false
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"rougail.my_var": {
|
||||
"owner": "default",
|
||||
"value": "no"
|
||||
},
|
||||
"rougail.server_deployed": {
|
||||
"owner": "default",
|
||||
"value": false
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
from importlib.machinery import SourceFileLoader as _SourceFileLoader
|
||||
from importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec
|
||||
class func:
|
||||
pass
|
||||
|
||||
def _load_functions(path):
|
||||
global _SourceFileLoader, _spec_from_loader, _module_from_spec, func
|
||||
loader = _SourceFileLoader('func', path)
|
||||
spec = _spec_from_loader(loader.name, loader)
|
||||
func_ = _module_from_spec(spec)
|
||||
loader.exec_module(func_)
|
||||
for function in dir(func_):
|
||||
if function.startswith('_'):
|
||||
continue
|
||||
setattr(func, function, getattr(func_, function))
|
||||
_load_functions('tests/dictionaries/../eosfunc/test.py')
|
||||
try:
|
||||
from tiramisu4 import *
|
||||
from tiramisu4.setting import ALLOWED_LEADER_PROPERTIES
|
||||
except:
|
||||
from tiramisu import *
|
||||
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||
ALLOWED_LEADER_PROPERTIES.add("normal")
|
||||
ALLOWED_LEADER_PROPERTIES.add("expert")
|
||||
option_2 = BoolOption(name="server_deployed", doc="server_deployed", default=False, properties=frozenset({"mandatory", "normal"}))
|
||||
option_1 = StrOption(name="my_var", doc="my_var", default="no", properties=frozenset({"expert", "force_store_value", "mandatory", Calculation(func.calc_value, Params(ParamValue('frozen'), kwargs={'condition': ParamOption(option_2, notraisepropertyerror=True), 'expected': ParamValue(True)}), func.calc_value_property_help)}))
|
||||
optiondescription_3 = OptionDescription(name="rougail", doc="Rougail", children=[option_1, option_2], properties=frozenset({"normal"}))
|
||||
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_3])
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
from importlib.machinery import SourceFileLoader as _SourceFileLoader
|
||||
from importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec
|
||||
class func:
|
||||
pass
|
||||
|
||||
def _load_functions(path):
|
||||
global _SourceFileLoader, _spec_from_loader, _module_from_spec, func
|
||||
loader = _SourceFileLoader('func', path)
|
||||
spec = _spec_from_loader(loader.name, loader)
|
||||
func_ = _module_from_spec(spec)
|
||||
loader.exec_module(func_)
|
||||
for function in dir(func_):
|
||||
if function.startswith('_'):
|
||||
continue
|
||||
setattr(func, function, getattr(func_, function))
|
||||
_load_functions('tests/dictionaries/../eosfunc/test.py')
|
||||
try:
|
||||
from tiramisu4 import *
|
||||
from tiramisu4.setting import ALLOWED_LEADER_PROPERTIES
|
||||
except:
|
||||
from tiramisu import *
|
||||
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||
ALLOWED_LEADER_PROPERTIES.add("normal")
|
||||
ALLOWED_LEADER_PROPERTIES.add("expert")
|
||||
option_2 = BoolOption(name="server_deployed", doc="server_deployed", default=False, properties=frozenset({"mandatory", "normal"}))
|
||||
option_1 = StrOption(name="my_var", doc="my_var", default="no", properties=frozenset({"expert", "force_store_value", "mandatory", Calculation(func.calc_value, Params(ParamValue('frozen'), kwargs={'condition': ParamOption(option_2, notraisepropertyerror=True), 'expected': ParamValue(True)}), func.calc_value_property_help)}))
|
||||
optiondescription_6 = OptionDescription(name="rougail", doc="Rougail", children=[option_1, option_2], properties=frozenset({"normal"}))
|
||||
optiondescription_5 = OptionDescription(name="1", doc="1", children=[optiondescription_6])
|
||||
option_4 = BoolOption(name="server_deployed", doc="server_deployed", default=False, properties=frozenset({"mandatory", "normal"}))
|
||||
option_3 = StrOption(name="my_var", doc="my_var", default="no", properties=frozenset({"expert", "force_store_value", "mandatory", Calculation(func.calc_value, Params(ParamValue('frozen'), kwargs={'condition': ParamOption(option_4, notraisepropertyerror=True), 'expected': ParamValue(True)}), func.calc_value_property_help)}))
|
||||
optiondescription_8 = OptionDescription(name="rougail", doc="Rougail", children=[option_3, option_4], properties=frozenset({"normal"}))
|
||||
optiondescription_7 = OptionDescription(name="2", doc="2", children=[optiondescription_8])
|
||||
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_5, optiondescription_7])
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<rougail version="0.10">
|
||||
<variables>
|
||||
<variable name="my_var" auto_freeze="True" mode="expert">
|
||||
<value>no</value>
|
||||
</variable>
|
||||
<variable name="server_deployed" type="boolean">
|
||||
<value>False</value>
|
||||
</variable>
|
||||
</variables>
|
||||
</rougail>
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
version: '0.10'
|
||||
variables:
|
||||
- variable:
|
||||
- name: my_var
|
||||
auto_freeze: true
|
||||
mode: expert
|
||||
value:
|
||||
- text: 'no'
|
||||
- name: server_deployed
|
||||
type: boolean
|
||||
value:
|
||||
- text: false
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"rougail.server_deployed": {
|
||||
"owner": "default",
|
||||
"value": true
|
||||
},
|
||||
"rougail.general.mode_conteneur_actif": {
|
||||
"owner": "forced",
|
||||
"value": "non"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"rougail.server_deployed": true,
|
||||
"rougail.general.mode_conteneur_actif": "non"
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"rougail.server_deployed": {
|
||||
"owner": "default",
|
||||
"value": true
|
||||
},
|
||||
"rougail.general.mode_conteneur_actif": {
|
||||
"owner": "default",
|
||||
"value": "non"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
from importlib.machinery import SourceFileLoader as _SourceFileLoader
|
||||
from importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec
|
||||
class func:
|
||||
pass
|
||||
|
||||
def _load_functions(path):
|
||||
global _SourceFileLoader, _spec_from_loader, _module_from_spec, func
|
||||
loader = _SourceFileLoader('func', path)
|
||||
spec = _spec_from_loader(loader.name, loader)
|
||||
func_ = _module_from_spec(spec)
|
||||
loader.exec_module(func_)
|
||||
for function in dir(func_):
|
||||
if function.startswith('_'):
|
||||
continue
|
||||
setattr(func, function, getattr(func_, function))
|
||||
_load_functions('tests/dictionaries/../eosfunc/test.py')
|
||||
try:
|
||||
from tiramisu4 import *
|
||||
from tiramisu4.setting import ALLOWED_LEADER_PROPERTIES
|
||||
except:
|
||||
from tiramisu import *
|
||||
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||
ALLOWED_LEADER_PROPERTIES.add("normal")
|
||||
ALLOWED_LEADER_PROPERTIES.add("expert")
|
||||
option_1 = BoolOption(name="server_deployed", doc="server_deployed", default=True, properties=frozenset({"mandatory", "normal"}))
|
||||
option_3 = StrOption(name="mode_conteneur_actif", doc="No change", default="non", properties=frozenset({"basic", "force_store_value", "mandatory"}))
|
||||
optiondescription_2 = OptionDescription(name="general", doc="général", children=[option_3], properties=frozenset({"basic"}))
|
||||
optiondescription_4 = OptionDescription(name="rougail", doc="Rougail", children=[option_1, optiondescription_2], properties=frozenset({"basic"}))
|
||||
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_4])
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"rougail.server_deployed": {
|
||||
"owner": "default",
|
||||
"value": true
|
||||
},
|
||||
"rougail.general.mode_conteneur_actif": {
|
||||
"owner": "forced",
|
||||
"value": "non"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"rougail.server_deployed": true,
|
||||
"rougail.general.mode_conteneur_actif": "non"
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"rougail.server_deployed": {
|
||||
"owner": "default",
|
||||
"value": true
|
||||
},
|
||||
"rougail.general.mode_conteneur_actif": {
|
||||
"owner": "default",
|
||||
"value": "non"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
from importlib.machinery import SourceFileLoader as _SourceFileLoader
|
||||
from importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec
|
||||
class func:
|
||||
pass
|
||||
|
||||
def _load_functions(path):
|
||||
global _SourceFileLoader, _spec_from_loader, _module_from_spec, func
|
||||
loader = _SourceFileLoader('func', path)
|
||||
spec = _spec_from_loader(loader.name, loader)
|
||||
func_ = _module_from_spec(spec)
|
||||
loader.exec_module(func_)
|
||||
for function in dir(func_):
|
||||
if function.startswith('_'):
|
||||
continue
|
||||
setattr(func, function, getattr(func_, function))
|
||||
_load_functions('tests/dictionaries/../eosfunc/test.py')
|
||||
try:
|
||||
from tiramisu4 import *
|
||||
from tiramisu4.setting import ALLOWED_LEADER_PROPERTIES
|
||||
except:
|
||||
from tiramisu import *
|
||||
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||
ALLOWED_LEADER_PROPERTIES.add("normal")
|
||||
ALLOWED_LEADER_PROPERTIES.add("expert")
|
||||
option_1 = BoolOption(name="server_deployed", doc="server_deployed", default=True, properties=frozenset({"mandatory", "normal"}))
|
||||
option_3 = StrOption(name="mode_conteneur_actif", doc="No change", default="non", properties=frozenset({"expert", "force_store_value", "mandatory"}))
|
||||
optiondescription_2 = OptionDescription(name="general", doc="général", children=[option_3], properties=frozenset({"expert"}))
|
||||
optiondescription_4 = OptionDescription(name="rougail", doc="Rougail", children=[option_1, optiondescription_2], properties=frozenset({"normal"}))
|
||||
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_4])
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
from importlib.machinery import SourceFileLoader as _SourceFileLoader
|
||||
from importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec
|
||||
class func:
|
||||
pass
|
||||
|
||||
def _load_functions(path):
|
||||
global _SourceFileLoader, _spec_from_loader, _module_from_spec, func
|
||||
loader = _SourceFileLoader('func', path)
|
||||
spec = _spec_from_loader(loader.name, loader)
|
||||
func_ = _module_from_spec(spec)
|
||||
loader.exec_module(func_)
|
||||
for function in dir(func_):
|
||||
if function.startswith('_'):
|
||||
continue
|
||||
setattr(func, function, getattr(func_, function))
|
||||
_load_functions('tests/dictionaries/../eosfunc/test.py')
|
||||
try:
|
||||
from tiramisu4 import *
|
||||
from tiramisu4.setting import ALLOWED_LEADER_PROPERTIES
|
||||
except:
|
||||
from tiramisu import *
|
||||
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||
ALLOWED_LEADER_PROPERTIES.add("normal")
|
||||
ALLOWED_LEADER_PROPERTIES.add("expert")
|
||||
option_2 = StrOption(name="mode_conteneur_actif", doc="No change", default="non", properties=frozenset({"force_default_on_freeze", "frozen", "hidden", "mandatory", "normal"}))
|
||||
optiondescription_1 = OptionDescription(name="general", doc="général", children=[option_2], properties=frozenset({"normal"}))
|
||||
optiondescription_3 = OptionDescription(name="rougail", doc="Rougail", children=[optiondescription_1], properties=frozenset({"normal"}))
|
||||
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_3])
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
general:
|
||||
description: général
|
||||
mode_conteneur_actif:
|
||||
type: string
|
||||
description: No change
|
||||
hidden: true
|
||||
default: non
|
||||
without_type:
|
||||
default: non
|
||||
version: '1.0'
|
||||
|
|
@ -1,7 +1,12 @@
|
|||
from tiramisu import *
|
||||
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||
ALLOWED_LEADER_PROPERTIES.add("normal")
|
||||
ALLOWED_LEADER_PROPERTIES.add("expert")
|
||||
from importlib.machinery import SourceFileLoader as _SourceFileLoader
|
||||
from importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec
|
||||
class func:
|
||||
pass
|
||||
global func
|
||||
func = {'calc_value': calc_value}
|
||||
|
||||
def _load_functions(path):
|
||||
global _SourceFileLoader, _spec_from_loader, _module_from_spec, func
|
||||
|
|
@ -12,19 +17,10 @@ def _load_functions(path):
|
|||
for function in dir(func_):
|
||||
if function.startswith('_'):
|
||||
continue
|
||||
setattr(func, function, getattr(func_, function))
|
||||
func[function] = getattr(func_, function)
|
||||
_load_functions('tests/dictionaries/../eosfunc/test.py')
|
||||
try:
|
||||
from tiramisu4 import *
|
||||
from tiramisu4.setting import ALLOWED_LEADER_PROPERTIES
|
||||
except:
|
||||
from tiramisu import *
|
||||
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||
ALLOWED_LEADER_PROPERTIES.add("normal")
|
||||
ALLOWED_LEADER_PROPERTIES.add("expert")
|
||||
option_2 = StrOption(name="mode_conteneur_actif", doc="No change", default="non", properties=frozenset({"force_default_on_freeze", "frozen", "hidden", "mandatory", "normal"}))
|
||||
option_3 = StrOption(name="without_type", doc="without_type", default="non", properties=frozenset({"mandatory", "normal"}))
|
||||
optiondescription_1 = OptionDescription(name="general", doc="général", children=[option_2, option_3], properties=frozenset({"normal"}))
|
||||
optiondescription_4 = OptionDescription(name="rougail", doc="Rougail", children=[optiondescription_1], properties=frozenset({"normal"}))
|
||||
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_4])
|
||||
option_3 = StrOption(name="mode_conteneur_actif", doc="No change", default="non", properties=frozenset({"force_default_on_freeze", "frozen", "hidden", "mandatory", "normal"}))
|
||||
option_4 = StrOption(name="without_type", doc="without_type", default="non", properties=frozenset({"mandatory", "normal"}))
|
||||
optiondescription_2 = OptionDescription(name="general", doc="général", children=[option_3, option_4], properties=frozenset({"normal"}))
|
||||
optiondescription_1 = OptionDescription(name="rougail", doc="rougail", children=[optiondescription_2], properties=frozenset({"normal"}))
|
||||
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
general:
|
||||
description: général
|
||||
mode_conteneur_actif:
|
||||
type: string
|
||||
description: No change
|
||||
hidden: true
|
||||
default: non
|
||||
version: '1.0'
|
||||
|
|
@ -1,7 +1,12 @@
|
|||
from tiramisu import *
|
||||
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||
ALLOWED_LEADER_PROPERTIES.add("normal")
|
||||
ALLOWED_LEADER_PROPERTIES.add("expert")
|
||||
from importlib.machinery import SourceFileLoader as _SourceFileLoader
|
||||
from importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec
|
||||
class func:
|
||||
pass
|
||||
global func
|
||||
func = {'calc_value': calc_value}
|
||||
|
||||
def _load_functions(path):
|
||||
global _SourceFileLoader, _spec_from_loader, _module_from_spec, func
|
||||
|
|
@ -12,18 +17,9 @@ def _load_functions(path):
|
|||
for function in dir(func_):
|
||||
if function.startswith('_'):
|
||||
continue
|
||||
setattr(func, function, getattr(func_, function))
|
||||
func[function] = getattr(func_, function)
|
||||
_load_functions('tests/dictionaries/../eosfunc/test.py')
|
||||
try:
|
||||
from tiramisu4 import *
|
||||
from tiramisu4.setting import ALLOWED_LEADER_PROPERTIES
|
||||
except:
|
||||
from tiramisu import *
|
||||
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||
ALLOWED_LEADER_PROPERTIES.add("normal")
|
||||
ALLOWED_LEADER_PROPERTIES.add("expert")
|
||||
option_2 = StrOption(name="mode_conteneur_actif", doc="No change", default="non", properties=frozenset({"force_default_on_freeze", "frozen", "hidden", "mandatory", "normal"}))
|
||||
optiondescription_1 = OptionDescription(name="general", doc="général", children=[option_2], properties=frozenset({"normal"}))
|
||||
optiondescription_3 = OptionDescription(name="rougail", doc="Rougail", children=[optiondescription_1], properties=frozenset({"normal"}))
|
||||
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_3])
|
||||
option_3 = StrOption(name="mode_conteneur_actif", doc="No change", default="non", properties=frozenset({"force_default_on_freeze", "frozen", "hidden", "mandatory", "normal"}))
|
||||
optiondescription_2 = OptionDescription(name="general", doc="général", children=[option_3], properties=frozenset({"normal"}))
|
||||
optiondescription_1 = OptionDescription(name="rougail", doc="rougail", children=[optiondescription_2], properties=frozenset({"normal"}))
|
||||
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
general:
|
||||
description: général
|
||||
mode_conteneur_actif:
|
||||
type: string
|
||||
description: No change
|
||||
hidden: true
|
||||
default: non
|
||||
version: '1.0'
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"rougail.server_deployed": {
|
||||
"owner": "default",
|
||||
"value": false
|
||||
},
|
||||
"rougail.my_variable": {
|
||||
"owner": "forced",
|
||||
"value": "yes"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"rougail.server_deployed": false,
|
||||
"rougail.my_variable": "yes"
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"rougail.server_deployed": {
|
||||
"owner": "default",
|
||||
"value": false
|
||||
},
|
||||
"rougail.my_variable": {
|
||||
"owner": "default",
|
||||
"value": "yes"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
from importlib.machinery import SourceFileLoader as _SourceFileLoader
|
||||
from importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec
|
||||
class func:
|
||||
pass
|
||||
|
||||
def _load_functions(path):
|
||||
global _SourceFileLoader, _spec_from_loader, _module_from_spec, func
|
||||
loader = _SourceFileLoader('func', path)
|
||||
spec = _spec_from_loader(loader.name, loader)
|
||||
func_ = _module_from_spec(spec)
|
||||
loader.exec_module(func_)
|
||||
for function in dir(func_):
|
||||
if function.startswith('_'):
|
||||
continue
|
||||
setattr(func, function, getattr(func_, function))
|
||||
_load_functions('tests/dictionaries/../eosfunc/test.py')
|
||||
try:
|
||||
from tiramisu4 import *
|
||||
from tiramisu4.setting import ALLOWED_LEADER_PROPERTIES
|
||||
except:
|
||||
from tiramisu import *
|
||||
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||
ALLOWED_LEADER_PROPERTIES.add("normal")
|
||||
ALLOWED_LEADER_PROPERTIES.add("expert")
|
||||
option_1 = BoolOption(name="server_deployed", doc="server_deployed", default=False, properties=frozenset({"mandatory", "normal"}))
|
||||
option_2 = StrOption(name="my_variable", doc="my_variable", default=Calculation(func.calc_val, Params((ParamValue("yes")))), properties=frozenset({"basic", "force_store_value", "hidden", Calculation(func.calc_value, Params(ParamValue('frozen'), kwargs={'condition': ParamOption(option_1, notraisepropertyerror=True), 'expected': ParamValue(True)}), func.calc_value_property_help)}))
|
||||
optiondescription_3 = OptionDescription(name="rougail", doc="Rougail", children=[option_1, option_2], properties=frozenset({"basic"}))
|
||||
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_3])
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
from importlib.machinery import SourceFileLoader as _SourceFileLoader
|
||||
from importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec
|
||||
class func:
|
||||
pass
|
||||
|
||||
def _load_functions(path):
|
||||
global _SourceFileLoader, _spec_from_loader, _module_from_spec, func
|
||||
loader = _SourceFileLoader('func', path)
|
||||
spec = _spec_from_loader(loader.name, loader)
|
||||
func_ = _module_from_spec(spec)
|
||||
loader.exec_module(func_)
|
||||
for function in dir(func_):
|
||||
if function.startswith('_'):
|
||||
continue
|
||||
setattr(func, function, getattr(func_, function))
|
||||
_load_functions('tests/dictionaries/../eosfunc/test.py')
|
||||
try:
|
||||
from tiramisu4 import *
|
||||
from tiramisu4.setting import ALLOWED_LEADER_PROPERTIES
|
||||
except:
|
||||
from tiramisu import *
|
||||
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||
ALLOWED_LEADER_PROPERTIES.add("normal")
|
||||
ALLOWED_LEADER_PROPERTIES.add("expert")
|
||||
option_1 = BoolOption(name="server_deployed", doc="server_deployed", default=False, properties=frozenset({"mandatory", "normal"}))
|
||||
option_2 = StrOption(name="my_variable", doc="my_variable", default=Calculation(func.calc_val, Params((ParamValue("yes")))), properties=frozenset({"basic", "force_store_value", "hidden", Calculation(func.calc_value, Params(ParamValue('frozen'), kwargs={'condition': ParamOption(option_1, notraisepropertyerror=True), 'expected': ParamValue(True)}), func.calc_value_property_help)}))
|
||||
optiondescription_6 = OptionDescription(name="rougail", doc="Rougail", children=[option_1, option_2], properties=frozenset({"basic"}))
|
||||
optiondescription_5 = OptionDescription(name="1", doc="1", children=[optiondescription_6])
|
||||
option_3 = BoolOption(name="server_deployed", doc="server_deployed", default=False, properties=frozenset({"mandatory", "normal"}))
|
||||
option_4 = StrOption(name="my_variable", doc="my_variable", default=Calculation(func.calc_val, Params((ParamValue("yes")))), properties=frozenset({"basic", "force_store_value", "hidden", Calculation(func.calc_value, Params(ParamValue('frozen'), kwargs={'condition': ParamOption(option_3, notraisepropertyerror=True), 'expected': ParamValue(True)}), func.calc_value_property_help)}))
|
||||
optiondescription_8 = OptionDescription(name="rougail", doc="Rougail", children=[option_3, option_4], properties=frozenset({"basic"}))
|
||||
optiondescription_7 = OptionDescription(name="2", doc="2", children=[optiondescription_8])
|
||||
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_5, optiondescription_7])
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<rougail version="0.10">
|
||||
<variables>
|
||||
<variable name="server_deployed" type="boolean">
|
||||
<value>False</value>
|
||||
</variable>
|
||||
<variable name="my_variable" auto_freeze="True" hidden="True">
|
||||
<value>no</value>
|
||||
</variable>
|
||||
</variables>
|
||||
<constraints>
|
||||
<fill name="calc_val">
|
||||
<param>yes</param>
|
||||
<target>my_variable</target>
|
||||
</fill>
|
||||
</constraints>
|
||||
</rougail>
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
version: '0.10'
|
||||
variables:
|
||||
- variable:
|
||||
- name: server_deployed
|
||||
type: boolean
|
||||
value:
|
||||
- text: false
|
||||
- name: my_variable
|
||||
auto_freeze: true
|
||||
hidden: true
|
||||
value:
|
||||
- text: 'no'
|
||||
constraints:
|
||||
- fill:
|
||||
- name: calc_val
|
||||
param:
|
||||
- text: 'yes'
|
||||
target:
|
||||
- text: my_variable
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
from importlib.machinery import SourceFileLoader as _SourceFileLoader
|
||||
from importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec
|
||||
class func:
|
||||
pass
|
||||
|
||||
def _load_functions(path):
|
||||
global _SourceFileLoader, _spec_from_loader, _module_from_spec, func
|
||||
loader = _SourceFileLoader('func', path)
|
||||
spec = _spec_from_loader(loader.name, loader)
|
||||
func_ = _module_from_spec(spec)
|
||||
loader.exec_module(func_)
|
||||
for function in dir(func_):
|
||||
if function.startswith('_'):
|
||||
continue
|
||||
setattr(func, function, getattr(func_, function))
|
||||
_load_functions('tests/dictionaries/../eosfunc/test.py')
|
||||
try:
|
||||
from tiramisu4 import *
|
||||
from tiramisu4.setting import ALLOWED_LEADER_PROPERTIES
|
||||
except:
|
||||
from tiramisu import *
|
||||
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||
ALLOWED_LEADER_PROPERTIES.add("normal")
|
||||
ALLOWED_LEADER_PROPERTIES.add("expert")
|
||||
option_3 = StrOption(name="mode_conteneur_actif1", doc="No change", default="non", properties=frozenset({"mandatory", "normal"}))
|
||||
option_2 = StrOption(name="mode_conteneur_actif", doc="No change", default=Calculation(func.calc_val, Params((ParamOption(option_3)))), properties=frozenset({"force_default_on_freeze", "frozen", "hidden", "normal"}))
|
||||
optiondescription_1 = OptionDescription(name="general", doc="general", children=[option_2, option_3], properties=frozenset({"normal"}))
|
||||
optiondescription_4 = OptionDescription(name="rougail", doc="Rougail", children=[optiondescription_1], properties=frozenset({"normal"}))
|
||||
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_4])
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
from importlib.machinery import SourceFileLoader as _SourceFileLoader
|
||||
from importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec
|
||||
class func:
|
||||
pass
|
||||
|
||||
def _load_functions(path):
|
||||
global _SourceFileLoader, _spec_from_loader, _module_from_spec, func
|
||||
loader = _SourceFileLoader('func', path)
|
||||
spec = _spec_from_loader(loader.name, loader)
|
||||
func_ = _module_from_spec(spec)
|
||||
loader.exec_module(func_)
|
||||
for function in dir(func_):
|
||||
if function.startswith('_'):
|
||||
continue
|
||||
setattr(func, function, getattr(func_, function))
|
||||
_load_functions('tests/dictionaries/../eosfunc/test.py')
|
||||
try:
|
||||
from tiramisu4 import *
|
||||
from tiramisu4.setting import ALLOWED_LEADER_PROPERTIES
|
||||
except:
|
||||
from tiramisu import *
|
||||
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||
ALLOWED_LEADER_PROPERTIES.add("normal")
|
||||
ALLOWED_LEADER_PROPERTIES.add("expert")
|
||||
from jinja2 import StrictUndefined, DictLoader
|
||||
from jinja2.sandbox import SandboxedEnvironment
|
||||
from rougail.annotator.variable import CONVERT_OPTION
|
||||
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
|
||||
kw = {}
|
||||
for key, value in kwargs.items():
|
||||
if '.' in key:
|
||||
c_kw = kw
|
||||
path, var = key.rsplit('.', 1)
|
||||
for subkey in path.split('.'):
|
||||
c_kw = c_kw.setdefault(subkey, {})
|
||||
c_kw[var] = value
|
||||
else:
|
||||
kw[key] = value
|
||||
values = ENV.get_template(__internal_jinja).render(kw)
|
||||
convert = CONVERT_OPTION[__internal_type].get('func', str)
|
||||
if __internal_multi:
|
||||
return [convert(val) for val in values.split(',')]
|
||||
return convert(values)
|
||||
def valid_with_jinja(value, **kwargs):
|
||||
kwargs[kwargs.pop('__internal_key')] = value
|
||||
value = jinja_to_function(__internal_type='string', __internal_multi=False, **kwargs)
|
||||
if value:
|
||||
raise ValueError(value)
|
||||
func.jinja_to_function = jinja_to_function
|
||||
func.valid_with_jinja = valid_with_jinja
|
||||
dict_env = {}
|
||||
dict_env['rougail.general.mode_conteneur_actif'] = "{{ mode_conteneur_actif1 }}"
|
||||
ENV = SandboxedEnvironment(loader=DictLoader(dict_env), undefined=StrictUndefined)
|
||||
ENV.compile_templates('jinja_caches', zip=None)
|
||||
option_3 = StrOption(name="mode_conteneur_actif1", doc="No change", default="non", properties=frozenset({"mandatory", "normal"}))
|
||||
option_2 = StrOption(name="mode_conteneur_actif", doc="No change", default=Calculation(func.jinja_to_function, Params((), kwargs={'__internal_jinja': ParamValue("rougail.general.mode_conteneur_actif"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(False), 'mode_conteneur_actif1': ParamOption(option_3)})), properties=frozenset({"force_default_on_freeze", "frozen", "hidden", "normal"}))
|
||||
optiondescription_1 = OptionDescription(name="general", doc="general", children=[option_2, option_3], properties=frozenset({"normal"}))
|
||||
optiondescription_4 = OptionDescription(name="rougail", doc="Rougail", children=[optiondescription_1], properties=frozenset({"normal"}))
|
||||
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_4])
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<rougail version="0.10">
|
||||
<variables>
|
||||
<family name="general">
|
||||
<variable name="mode_conteneur_actif" type="string" description="No change" hidden="True">
|
||||
<value>non</value>
|
||||
</variable>
|
||||
<variable name="mode_conteneur_actif1" type="string" description="No change">
|
||||
<value>non</value>
|
||||
</variable>
|
||||
</family>
|
||||
</variables>
|
||||
<constraints>
|
||||
<fill name="{{ mode_conteneur_actif1 }}" type="jinja">
|
||||
<target>mode_conteneur_actif</target>
|
||||
</fill>
|
||||
</constraints>
|
||||
</rougail>
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"rougail.general.mode_conteneur_actif": {
|
||||
"owner": "default",
|
||||
"value": "non"
|
||||
},
|
||||
"rougail.general.mode_conteneur_actif1": {
|
||||
"owner": "default",
|
||||
"value": "non"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"rougail.general.mode_conteneur_actif": "non",
|
||||
"rougail.general.mode_conteneur_actif1": "non"
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"rougail.general.mode_conteneur_actif": {
|
||||
"owner": "default",
|
||||
"value": "non"
|
||||
},
|
||||
"rougail.general.mode_conteneur_actif1": {
|
||||
"owner": "default",
|
||||
"value": "non"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
from importlib.machinery import SourceFileLoader as _SourceFileLoader
|
||||
from importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec
|
||||
class func:
|
||||
pass
|
||||
|
||||
def _load_functions(path):
|
||||
global _SourceFileLoader, _spec_from_loader, _module_from_spec, func
|
||||
loader = _SourceFileLoader('func', path)
|
||||
spec = _spec_from_loader(loader.name, loader)
|
||||
func_ = _module_from_spec(spec)
|
||||
loader.exec_module(func_)
|
||||
for function in dir(func_):
|
||||
if function.startswith('_'):
|
||||
continue
|
||||
setattr(func, function, getattr(func_, function))
|
||||
_load_functions('tests/dictionaries/../eosfunc/test.py')
|
||||
try:
|
||||
from tiramisu4 import *
|
||||
from tiramisu4.setting import ALLOWED_LEADER_PROPERTIES
|
||||
except:
|
||||
from tiramisu import *
|
||||
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||
ALLOWED_LEADER_PROPERTIES.add("normal")
|
||||
ALLOWED_LEADER_PROPERTIES.add("expert")
|
||||
from jinja2 import StrictUndefined, DictLoader
|
||||
from jinja2.sandbox import SandboxedEnvironment
|
||||
from rougail.annotator.variable import CONVERT_OPTION
|
||||
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
|
||||
kw = {}
|
||||
for key, value in kwargs.items():
|
||||
if '.' in key:
|
||||
c_kw = kw
|
||||
path, var = key.rsplit('.', 1)
|
||||
for subkey in path.split('.'):
|
||||
c_kw = c_kw.setdefault(subkey, {})
|
||||
c_kw[var] = value
|
||||
else:
|
||||
kw[key] = value
|
||||
values = ENV.get_template(__internal_jinja).render(kw)
|
||||
convert = CONVERT_OPTION[__internal_type].get('func', str)
|
||||
if __internal_multi:
|
||||
return [convert(val) for val in values.split(',')]
|
||||
return convert(values)
|
||||
def valid_with_jinja(value, **kwargs):
|
||||
kwargs[kwargs.pop('__internal_key')] = value
|
||||
value = jinja_to_function(__internal_type='string', __internal_multi=False, **kwargs)
|
||||
if value:
|
||||
raise ValueError(value)
|
||||
func.jinja_to_function = jinja_to_function
|
||||
func.valid_with_jinja = valid_with_jinja
|
||||
dict_env = {}
|
||||
dict_env['rougail.general.mode_conteneur_actif'] = "{{ rougail.general.mode_conteneur_actif1 }}"
|
||||
ENV = SandboxedEnvironment(loader=DictLoader(dict_env), undefined=StrictUndefined)
|
||||
ENV.compile_templates('jinja_caches', zip=None)
|
||||
option_3 = StrOption(name="mode_conteneur_actif1", doc="No change", default="non", properties=frozenset({"mandatory", "normal"}))
|
||||
option_2 = StrOption(name="mode_conteneur_actif", doc="No change", default=Calculation(func.jinja_to_function, Params((), kwargs={'__internal_jinja': ParamValue("rougail.general.mode_conteneur_actif"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(False), 'rougail.general.mode_conteneur_actif1': ParamOption(option_3)})), properties=frozenset({"force_default_on_freeze", "frozen", "hidden", "normal"}))
|
||||
optiondescription_1 = OptionDescription(name="general", doc="general", children=[option_2, option_3], properties=frozenset({"normal"}))
|
||||
optiondescription_4 = OptionDescription(name="rougail", doc="Rougail", children=[optiondescription_1], properties=frozenset({"normal"}))
|
||||
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_4])
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
from importlib.machinery import SourceFileLoader as _SourceFileLoader
|
||||
from importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec
|
||||
class func:
|
||||
pass
|
||||
|
||||
def _load_functions(path):
|
||||
global _SourceFileLoader, _spec_from_loader, _module_from_spec, func
|
||||
loader = _SourceFileLoader('func', path)
|
||||
spec = _spec_from_loader(loader.name, loader)
|
||||
func_ = _module_from_spec(spec)
|
||||
loader.exec_module(func_)
|
||||
for function in dir(func_):
|
||||
if function.startswith('_'):
|
||||
continue
|
||||
setattr(func, function, getattr(func_, function))
|
||||
_load_functions('tests/dictionaries/../eosfunc/test.py')
|
||||
try:
|
||||
from tiramisu4 import *
|
||||
from tiramisu4.setting import ALLOWED_LEADER_PROPERTIES
|
||||
except:
|
||||
from tiramisu import *
|
||||
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||
ALLOWED_LEADER_PROPERTIES.add("normal")
|
||||
ALLOWED_LEADER_PROPERTIES.add("expert")
|
||||
from jinja2 import StrictUndefined, DictLoader
|
||||
from jinja2.sandbox import SandboxedEnvironment
|
||||
from rougail.annotator.variable import CONVERT_OPTION
|
||||
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
|
||||
kw = {}
|
||||
for key, value in kwargs.items():
|
||||
if '.' in key:
|
||||
c_kw = kw
|
||||
path, var = key.rsplit('.', 1)
|
||||
for subkey in path.split('.'):
|
||||
c_kw = c_kw.setdefault(subkey, {})
|
||||
c_kw[var] = value
|
||||
else:
|
||||
kw[key] = value
|
||||
values = ENV.get_template(__internal_jinja).render(kw)
|
||||
convert = CONVERT_OPTION[__internal_type].get('func', str)
|
||||
if __internal_multi:
|
||||
return [convert(val) for val in values.split(',')]
|
||||
return convert(values)
|
||||
def valid_with_jinja(value, **kwargs):
|
||||
kwargs[kwargs.pop('__internal_key')] = value
|
||||
value = jinja_to_function(__internal_type='string', __internal_multi=False, **kwargs)
|
||||
if value:
|
||||
raise ValueError(value)
|
||||
func.jinja_to_function = jinja_to_function
|
||||
func.valid_with_jinja = valid_with_jinja
|
||||
dict_env = {}
|
||||
dict_env['rougail.general.mode_conteneur_actif'] = "{% if mode_conteneur_actif1 == 'non' %}non{% else %}oui{% endif %}"
|
||||
dict_env['rougail.general.mode_conteneur_actif2'] = "{% if mode_conteneur_actif1 == \"non\" %}oui{% else %}non{% endif %}"
|
||||
ENV = SandboxedEnvironment(loader=DictLoader(dict_env), undefined=StrictUndefined)
|
||||
ENV.compile_templates('jinja_caches', zip=None)
|
||||
option_3 = StrOption(name="mode_conteneur_actif1", doc="No change", default="non", properties=frozenset({"mandatory", "normal"}))
|
||||
option_2 = StrOption(name="mode_conteneur_actif", doc="No change", default=Calculation(func.jinja_to_function, Params((), kwargs={'__internal_jinja': ParamValue("rougail.general.mode_conteneur_actif"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(False), 'mode_conteneur_actif1': ParamOption(option_3)})), properties=frozenset({"force_default_on_freeze", "frozen", "hidden", "normal"}))
|
||||
option_4 = StrOption(name="mode_conteneur_actif2", doc="No change", default=Calculation(func.jinja_to_function, Params((), kwargs={'__internal_jinja': ParamValue("rougail.general.mode_conteneur_actif2"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(False), 'mode_conteneur_actif1': ParamOption(option_3)})), properties=frozenset({"force_default_on_freeze", "frozen", "hidden", "normal"}))
|
||||
optiondescription_1 = OptionDescription(name="general", doc="general", children=[option_2, option_3, option_4], properties=frozenset({"normal"}))
|
||||
optiondescription_5 = OptionDescription(name="rougail", doc="Rougail", children=[optiondescription_1], properties=frozenset({"normal"}))
|
||||
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_5])
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
from importlib.machinery import SourceFileLoader as _SourceFileLoader
|
||||
from importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec
|
||||
class func:
|
||||
pass
|
||||
|
||||
def _load_functions(path):
|
||||
global _SourceFileLoader, _spec_from_loader, _module_from_spec, func
|
||||
loader = _SourceFileLoader('func', path)
|
||||
spec = _spec_from_loader(loader.name, loader)
|
||||
func_ = _module_from_spec(spec)
|
||||
loader.exec_module(func_)
|
||||
for function in dir(func_):
|
||||
if function.startswith('_'):
|
||||
continue
|
||||
setattr(func, function, getattr(func_, function))
|
||||
_load_functions('tests/dictionaries/../eosfunc/test.py')
|
||||
try:
|
||||
from tiramisu4 import *
|
||||
from tiramisu4.setting import ALLOWED_LEADER_PROPERTIES
|
||||
except:
|
||||
from tiramisu import *
|
||||
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||
ALLOWED_LEADER_PROPERTIES.add("normal")
|
||||
ALLOWED_LEADER_PROPERTIES.add("expert")
|
||||
from jinja2 import StrictUndefined, DictLoader
|
||||
from jinja2.sandbox import SandboxedEnvironment
|
||||
from rougail.annotator.variable import CONVERT_OPTION
|
||||
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
|
||||
kw = {}
|
||||
for key, value in kwargs.items():
|
||||
if '.' in key:
|
||||
c_kw = kw
|
||||
path, var = key.rsplit('.', 1)
|
||||
for subkey in path.split('.'):
|
||||
c_kw = c_kw.setdefault(subkey, {})
|
||||
c_kw[var] = value
|
||||
else:
|
||||
kw[key] = value
|
||||
values = ENV.get_template(__internal_jinja).render(kw)
|
||||
convert = CONVERT_OPTION[__internal_type].get('func', str)
|
||||
if __internal_multi:
|
||||
return [convert(val) for val in values.split(',')]
|
||||
return convert(values)
|
||||
def valid_with_jinja(value, **kwargs):
|
||||
kwargs[kwargs.pop('__internal_key')] = value
|
||||
value = jinja_to_function(__internal_type='string', __internal_multi=False, **kwargs)
|
||||
if value:
|
||||
raise ValueError(value)
|
||||
func.jinja_to_function = jinja_to_function
|
||||
func.valid_with_jinja = valid_with_jinja
|
||||
dict_env = {}
|
||||
dict_env['rougail.general.multi1'] = "{% if bool %}True,False{% else %}False{% endif %}"
|
||||
dict_env['rougail.general.multi2'] = "{% if not bool %}True,False{% else %}False{% endif %}"
|
||||
ENV = SandboxedEnvironment(loader=DictLoader(dict_env), undefined=StrictUndefined)
|
||||
ENV.compile_templates('jinja_caches', zip=None)
|
||||
option_2 = BoolOption(name="bool", doc="bool", default=True, properties=frozenset({"mandatory", "normal"}))
|
||||
option_3 = BoolOption(name="multi1", doc="multi1", multi=True, default=Calculation(func.jinja_to_function, Params((), kwargs={'__internal_jinja': ParamValue("rougail.general.multi1"), '__internal_type': ParamValue("boolean"), '__internal_multi': ParamValue(True), 'bool': ParamOption(option_2)})), properties=frozenset({"normal"}))
|
||||
option_4 = BoolOption(name="multi2", doc="multi2", multi=True, default=Calculation(func.jinja_to_function, Params((), kwargs={'__internal_jinja': ParamValue("rougail.general.multi2"), '__internal_type': ParamValue("boolean"), '__internal_multi': ParamValue(True), 'bool': ParamOption(option_2)})), properties=frozenset({"normal"}))
|
||||
optiondescription_1 = OptionDescription(name="general", doc="general", children=[option_2, option_3, option_4], properties=frozenset({"normal"}))
|
||||
optiondescription_5 = OptionDescription(name="rougail", doc="Rougail", children=[optiondescription_1], properties=frozenset({"normal"}))
|
||||
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_5])
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<rougail version="0.10">
|
||||
<variables>
|
||||
<family name="general">
|
||||
<variable name="bool" type="boolean"/>
|
||||
<variable name="multi1" type="boolean" multi="True"/>
|
||||
<variable name="multi2" type="boolean" multi="True"/>
|
||||
</family>
|
||||
</variables>
|
||||
<constraints>
|
||||
<fill name="{% if bool %}True,False{% else %}False{% endif %}" type="jinja">
|
||||
<target>multi1</target>
|
||||
</fill>
|
||||
<fill name="{% if not bool %}True,False{% else %}False{% endif %}" type="jinja">
|
||||
<target>multi2</target>
|
||||
</fill>
|
||||
</constraints>
|
||||
</rougail>
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue