Compare commits
342 commits
main
...
docs_updat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26362769ac | ||
| f134e96257 | |||
|
|
afa1cf3493 | ||
| b9ed3235a5 | |||
| 4440c96b6d | |||
| 8103ff2ff4 | |||
| 2557e9e2da | |||
| 3be1324da3 | |||
| 2e826db3f4 | |||
| a71a68a02a | |||
| 200a05f942 | |||
| 4c812ae299 | |||
| 215827f288 | |||
| 335e971aea | |||
| c733743048 | |||
| 3a32dd15af | |||
|
|
a621c1ed23 | ||
|
|
d73e0ee259 | ||
|
|
c15ed38624 | ||
|
|
37f146e314 | ||
|
|
7200b16fa1 | ||
|
|
4ba57ca6d6 | ||
|
|
e6c46fcd1b | ||
|
|
ccbd056c80 | ||
| 4cad2ce30f | |||
|
|
570b22525b | ||
| a18a39425d | |||
| 53c3cf316f | |||
|
|
2508087841 | ||
|
|
01504bb244 | ||
|
|
623d6ce584 | ||
| bcf4ff16ff | |||
|
|
84286156ba | ||
|
|
383c485c7a | ||
|
|
c50ce5bcc5 | ||
| 5386fa5178 | |||
| 40dadd6cba | |||
| fa2297ec88 | |||
| 64d0bfa802 | |||
| efcdc496ec | |||
|
|
6a641af563 | ||
| c324ac8913 | |||
|
|
ba8d3939fe | ||
|
|
d0bc7eabc7 | ||
| a2804aacf6 | |||
|
|
5c415fcac6 | ||
|
|
a923f496a0 | ||
| 322f1acd98 | |||
| 3b6fa2630b | |||
|
|
d92fd177a8 | ||
|
|
8696821442 | ||
|
|
13738fd4bf | ||
|
|
7b58d9a774 | ||
|
|
b259da3aef | ||
| 786eda74ce | |||
| 484a4ad92c | |||
|
|
9dfdf908f0 | ||
| 4fb075b451 | |||
|
|
fc480ef248 | ||
|
|
009136fa10 | ||
|
|
66bf59fe58 | ||
|
|
9f28248903 | ||
|
|
26b5d8dd10 | ||
| f89fb5ac7f | |||
| 5be6baab1a | |||
|
|
311b046f2b | ||
|
|
441260bea3 | ||
| 3372d45abc | |||
|
|
800a61bbf4 | ||
|
|
af513c6608 | ||
|
|
838a3c70e7 | ||
|
|
c36830d258 | ||
|
|
af57c8349c | ||
|
|
7afb2c860c | ||
| c72b34cbf9 | |||
|
|
4039e01769 | ||
| 647eb7c45d | |||
|
|
eb38aefdee | ||
|
|
2edf7bd91c | ||
|
|
e40ade0b64 | ||
| c0308145d5 | |||
| 4756e84d2e | |||
| 2d2adf8972 | |||
| 6825996918 | |||
|
|
fade50baf5 | ||
|
|
bc509a6fcf | ||
|
|
d6dcc712fb | ||
|
|
93800b558b | ||
|
|
a7af31bb50 | ||
|
|
28d2200915 | ||
|
|
58900a412b | ||
| b349ac5b1e | |||
|
|
88b7d46f60 | ||
|
|
a44087e3b3 | ||
|
|
f3cd0a03e9 | ||
|
|
bfdb4d3046 | ||
|
|
d7e1794648 | ||
|
|
f37c8f19d2 | ||
|
|
e07e2c618c | ||
|
|
8cc24d8ee4 | ||
|
|
a2b02a8552 | ||
|
|
d339aebd63 | ||
|
|
15bda31c7c | ||
|
|
250f63d8e1 | ||
|
|
81c40d6eb2 | ||
|
|
65009bb6f7 | ||
|
|
7962c35628 | ||
|
|
820fb9c736 | ||
|
|
64229f9169 | ||
| d68641410d | |||
| 06d36d0a36 | |||
|
|
3a9545c9cf | ||
|
|
40f59e83a6 | ||
| fe0488b8d3 | |||
|
|
38fad60219 | ||
|
|
1c91020981 | ||
|
|
fed4e414d0 | ||
|
|
f2473f85f8 | ||
|
|
9c0ee92892 | ||
|
|
2608958574 | ||
|
|
00d17badf8 | ||
|
|
c9d32dce9f | ||
|
|
9a834b637b | ||
|
|
186a3269d3 | ||
|
|
3293800c4c | ||
|
|
847205938d | ||
|
|
5039060012 | ||
|
|
e840bc5289 | ||
|
|
cb425ed7f7 | ||
|
|
c7156ea638 | ||
| f5f52b176a | |||
| e3e9ebac12 | |||
| 7878716ea1 | |||
|
|
3bfb517087 | ||
|
|
7b5c7b80ec | ||
|
|
480b5dbafb | ||
|
|
f85d95e599 | ||
|
|
78aa9a057a | ||
|
|
13b77b38f6 | ||
|
|
4585d1aa66 | ||
|
|
887f5794af | ||
|
|
c368334d05 | ||
|
|
4f87d9d5b9 | ||
|
|
096925eba7 | ||
|
|
9a78088cc6 | ||
|
|
ed09bfd4ae | ||
|
|
10eee79dc2 | ||
|
|
c08a1fca3a | ||
| 08c6a9e027 | |||
|
|
26a9a7edf9 | ||
|
|
9d0f0e9ae9 | ||
|
|
1e6331f477 | ||
|
|
a346e23af6 | ||
|
|
9c9c313681 | ||
|
|
2cf3b0e752 | ||
|
|
095f0be622 | ||
|
|
ff9c0650fc | ||
|
|
3823642352 | ||
|
|
7faf7c4310 | ||
|
|
b1f0e7e3de | ||
|
|
c0a6ef2223 | ||
|
|
44d848b943 | ||
|
|
6da067f206 | ||
|
|
eeba802047 | ||
|
|
9f2299ee3e | ||
|
|
0008d03772 | ||
|
|
d47405c61d | ||
| 8b02c79dcc | |||
|
|
aabc937d1c | ||
|
|
fe4e98624a | ||
|
|
c850c11e98 | ||
|
|
01c4325b86 | ||
|
|
01d99cbd01 | ||
|
|
0a10dfbd7d | ||
|
|
b437572de9 | ||
|
|
921fc0f481 | ||
|
|
a9b6a00087 | ||
|
|
d9ac902740 | ||
|
|
b22c1817b9 | ||
|
|
8e2fcd073d | ||
|
|
9413831037 | ||
|
|
9d5ca18bdc | ||
|
|
8bc7c9b04d | ||
|
|
40df27bf90 | ||
|
|
65d4440694 | ||
|
|
be4983e524 | ||
|
|
920780384d | ||
|
|
e61ff106eb | ||
|
|
cb9b534669 | ||
|
|
50bf8e696d | ||
|
|
76e59b22dd | ||
|
|
4057ef6fc7 | ||
|
|
f1af25d11a | ||
|
|
9ca4f31986 | ||
|
|
b5c919dc8d | ||
|
|
1364b3b4f2 | ||
|
|
2e99a30e38 | ||
| 1cd89747de | |||
|
|
22c7472297 | ||
|
|
778a8f5e48 | ||
|
|
7980e9f034 | ||
|
|
dbe78f2334 | ||
|
|
7fc56b2429 | ||
|
|
4da1408c7f | ||
|
|
99394348b5 | ||
|
|
cb52c774be | ||
|
|
2b0dd5e5bd | ||
| 9c2885ce94 | |||
| d3bfa99ee4 | |||
| 543d33a29b | |||
| 6c210f3c33 | |||
| 1adae63e18 | |||
|
|
9d6778ce4f | ||
|
|
f0018fcf93 | ||
|
|
043038526d | ||
|
|
20b90f7c70 | ||
|
|
9d67d93107 | ||
|
|
947ae2a029 | ||
|
|
55213e18db | ||
|
|
638442273b | ||
|
|
a0e556e7c1 | ||
| aca97a3e92 | |||
| bc0de749c7 | |||
|
|
9961d1c958 | ||
|
|
8912e6dd63 | ||
|
|
f3c3fe4df0 | ||
|
|
c378fbbf89 | ||
|
|
82b934db02 | ||
|
|
7f4efef0be | ||
|
|
e511f07932 | ||
|
|
e64a89990d | ||
|
|
5cc1e50669 | ||
|
|
7a20515114 | ||
| 5b1356970f | |||
| bc415deba9 | |||
|
|
6a87c23e2b | ||
|
|
42d5762a5f | ||
|
|
22a5621c5d | ||
| 9d856f9de0 | |||
| 2eeedd70e2 | |||
| 4bb50361d5 | |||
| 360c97c581 | |||
| 1277cce9d9 | |||
| 96975461d0 | |||
|
|
961cee372e | ||
|
|
16af68e9c8 | ||
|
|
6505ac9ab9 | ||
|
|
6b6aeceb6e | ||
|
|
91112a905a | ||
|
|
1da10b7970 | ||
|
|
15bd2c4986 | ||
|
|
8a7959ed11 | ||
|
|
ad80093520 | ||
|
|
7e163e56f0 | ||
|
|
f7701917d0 | ||
|
|
a3d7258a64 | ||
|
|
c2e8e3fd5a | ||
|
|
8d7dde7bcc | ||
|
|
ad2c9cf2ce | ||
|
|
0293d4d455 | ||
|
|
dd0ae7d03b | ||
|
|
e49f731aa2 | ||
|
|
284a176a0a | ||
|
|
edde6e2a85 | ||
|
|
3aed61cdb1 | ||
|
|
4af0e7cbe2 | ||
|
|
935b33d28e | ||
|
|
91ffd19336 | ||
|
|
fce54f7c84 | ||
|
|
cfb6017f32 | ||
|
|
a932d7e1c3 | ||
|
|
2da85eb0e8 | ||
|
|
9ca27d7f51 | ||
|
|
2d39fe8bad | ||
|
|
10a25b0cfe | ||
|
|
0f0d955e9f | ||
|
|
038cd9429a | ||
|
|
cc54cf675f | ||
|
|
b4efbf1d71 | ||
|
|
28fe83cfb2 | ||
|
|
6edda03d79 | ||
|
|
55bda5cd8c | ||
|
|
543d54144b | ||
|
|
98f788ee9b | ||
|
|
bf6120f95e | ||
|
|
04f30963f4 | ||
|
|
eda0632809 | ||
|
|
c2111fe581 | ||
|
|
9870d949b9 | ||
|
|
5dc7d2b630 | ||
|
|
fbc0744f61 | ||
|
|
d7b2e9b521 | ||
|
|
5cf4fb16a4 | ||
|
|
a0546a137f | ||
|
|
b1ed2d3aaf | ||
|
|
39f01b36a1 | ||
|
|
c361629b63 | ||
|
|
45b9a5495e | ||
|
|
19ecc56316 | ||
|
|
0ce1550028 | ||
|
|
cd850f1089 | ||
|
|
a310b6f063 | ||
|
|
50299203af | ||
|
|
080bb9c489 | ||
|
|
d47011efe4 | ||
|
|
9a84e28765 | ||
|
|
c244a816f3 | ||
|
|
9199631ea5 | ||
| 2d02da9939 | |||
| 06bb8f8fad | |||
| e2eb58664a | |||
| 2c0763c516 | |||
| ccb4eff30b | |||
| 7bdc39e370 | |||
| ea93bc55fc | |||
| ec86795768 | |||
| 810d08822b | |||
| 83840e329c | |||
| 1389929371 | |||
| b21c13fea7 | |||
| a827ca2225 | |||
| 75778cb39e | |||
| 9e614eb7a4 | |||
| 90ef65dd40 | |||
|
|
fd5b702686 | ||
| d4167b1586 | |||
| 161985ab50 | |||
| 908356495b | |||
| eb561f5f52 | |||
| 539ecc7412 | |||
|
|
b39b728a90 | ||
|
|
80e3b73785 | ||
|
|
a7c862cccd | ||
| e2d62211ec | |||
| 9705830e88 | |||
| 0a9d1b3014 | |||
|
|
4f33b7c7af | ||
| bdd56d31c8 | |||
|
|
6f9a981da7 | ||
|
|
4c6f451045 | ||
|
|
fc8c1ecfda | ||
|
|
7f7fe5f08f |
57
CHANGELOG.md
|
|
@ -1,60 +1,3 @@
|
|||
## 1.1.1 (2024-11-06)
|
||||
|
||||
### Fix
|
||||
|
||||
- upgrade tests
|
||||
|
||||
## 1.1.1rc0 (2024-11-06)
|
||||
|
||||
### Fix
|
||||
|
||||
- update tiramisu dependency
|
||||
- better user information if a needed package is not installed
|
||||
- **37**: import doesn't works for some python version
|
||||
- **36**: format 1.0: suffix attribut must works
|
||||
- update fr/rougail.mo
|
||||
|
||||
## 1.1.0 (2024-11-01)
|
||||
|
||||
### Fix
|
||||
|
||||
- black
|
||||
- add changelog_merge_prerelease to commitizen
|
||||
|
||||
## 1.1.0rc0 (2024-11-01)
|
||||
|
||||
### Feat
|
||||
|
||||
- update dependencies
|
||||
- translation
|
||||
- in calculation better debugging
|
||||
- can sort dictionaries in different directories
|
||||
- suffix to identifier
|
||||
- better errors messages and improvement
|
||||
- better debugging
|
||||
- update upgrade module
|
||||
- auto add multi for leader
|
||||
- use suffix in property calculation
|
||||
- in structural commandline very is there is conflict alternative name
|
||||
- **#21**: add examples attributes
|
||||
- **#23**: define easily a regexoption
|
||||
- add relative path support
|
||||
- add default inference for basic types
|
||||
- suffixes in dynamic family should be a jinja function (#5)
|
||||
- we should be able to customize a new variable type
|
||||
|
||||
### Fix
|
||||
|
||||
- support for unknown language
|
||||
- license
|
||||
- README
|
||||
- use black
|
||||
- valid mode even if there is no mode configured
|
||||
- valid mode if no mode defined
|
||||
- update tests
|
||||
- type is not always mandatory
|
||||
- auto_save in follower is now allowed in tiramisu
|
||||
|
||||
## 1.0.2 (2024-01-28)
|
||||
|
||||
### Fix
|
||||
|
|
|
|||
326
LICENSE
|
|
@ -1,165 +1,235 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
Preamble
|
||||
|
||||
0. Additional Definitions.
|
||||
The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public.
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
The precise terms and conditions for copying, distribution and modification follow.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
0. Definitions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
"The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
A "covered work" means either the unmodified Program or a work based on the Program.
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
4. Combined Works.
|
||||
An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
1. Source Code.
|
||||
The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work.
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
d) Do one of the following:
|
||||
The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
The Corresponding Source for a work in source code form is that same work.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
2. Basic Permissions.
|
||||
All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.
|
||||
|
||||
5. Combined Libraries.
|
||||
Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
4. Conveying Verbatim Copies.
|
||||
You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
5. Conveying Modified Source Versions.
|
||||
You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
a) The work must carry prominent notices stating that you modified it, and giving a relevant date.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
"Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see <http://www.gnu.org/licenses/>.
|
||||
|
|
|
|||
37
README.md
|
|
@ -28,27 +28,20 @@ Create the file `dict/dictionary.yml`:
|
|||
|
||||
```yml
|
||||
---
|
||||
version: 1.1
|
||||
version: '1.0'
|
||||
# describe a variable my_first_variable
|
||||
# and a family with a variable my_second_variable
|
||||
my_first_variable: my_value
|
||||
my_first_variable:
|
||||
default: my_value
|
||||
my_family:
|
||||
my_second_variable: 1
|
||||
my_second_variable:
|
||||
type: number
|
||||
mandatory: true
|
||||
value: 1
|
||||
```
|
||||
|
||||
## Generate variable
|
||||
|
||||
### With commandline:
|
||||
|
||||
```bash
|
||||
# rougail -m dict
|
||||
Variables:
|
||||
┣━━ 📓 my_first_variable: my_value
|
||||
┗━━ 📂 my_family
|
||||
┗━━ 📓 my_second_variable: 1
|
||||
|
||||
```
|
||||
|
||||
### With default value:
|
||||
|
||||
Here is a python3 example file:
|
||||
|
|
@ -58,16 +51,19 @@ from rougail import Rougail, RougailConfig
|
|||
from pprint import pprint
|
||||
|
||||
RougailConfig['dictionaries_dir'] = ['dict']
|
||||
RougailConfig['templates_dir'] = ['tmpl']
|
||||
RougailConfig['tmp_dir'] = 'tmp'
|
||||
RougailConfig['destinations_dir'] = 'dest'
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
config = rougail.get_config()
|
||||
pprint(config.value.get(), sort_dicts=False)
|
||||
```
|
||||
|
||||
The result is:
|
||||
|
||||
```json
|
||||
{<TiramisuOption path="rougail">: {<TiramisuOption path="rougail.my_first_variable">: 'my_value',
|
||||
<TiramisuOption path="rougail.my_family">: {<TiramisuOption path="rougail.my_family.my_second_variable">: 1}}}
|
||||
{'rougail.my_first_variable': 'my_value',
|
||||
'rougail.my_family.my_second_variable': 1}
|
||||
```
|
||||
|
||||
### With modified value
|
||||
|
|
@ -80,6 +76,9 @@ from rougail import Rougail, RougailConfig
|
|||
from pprint import pprint
|
||||
|
||||
RougailConfig['dictionaries_dir'] = ['dict']
|
||||
RougailConfig['templates_dir'] = ['tmpl']
|
||||
RougailConfig['tmp_dir'] = 'tmp'
|
||||
RougailConfig['destinations_dir'] = 'dest'
|
||||
rougail = Rougail()
|
||||
config = rougail.get_config()
|
||||
config.option('rougail.my_first_variable').value.set('modified_value')
|
||||
|
|
@ -90,8 +89,8 @@ pprint(config.value.get(), sort_dicts=False)
|
|||
The destination file is generated with new values:
|
||||
|
||||
```json
|
||||
{<TiramisuOption path="rougail">: {<TiramisuOption path="rougail.my_first_variable">: 'modified_value',
|
||||
<TiramisuOption path="rougail.my_family">: {<TiramisuOption path="rougail.my_family.my_second_variable">: 2}}}
|
||||
{'rougail.my_first_variable': 'modified_value',
|
||||
'rougail.my_family.my_second_variable': 2}
|
||||
```
|
||||
|
||||
# Link
|
||||
|
|
|
|||
940
caracteristique.md
Normal file
|
|
@ -0,0 +1,940 @@
|
|||
---
|
||||
gitea: none
|
||||
include_toc: true
|
||||
---
|
||||
|
||||
# Rougail : caractéristiques
|
||||
|
||||
Rougail est un outil qui permet de gérer le cycle de vie des variables et de gestion des valeurs de ces variables.
|
||||
|
||||
Au moment de la conception de Rougail, il y a eu des choix structurant qui ont défini le fonctionnement de l'outil.
|
||||
|
||||
Voici la liste des principales caractéristiques :
|
||||
|
||||
|
||||
## Logiciel libre
|
||||
|
||||
Rougail est un logiciel libre (et Open Source) de gestion externe de variables.
|
||||
Le développement est réalisé de manière ouverte.
|
||||
|
||||
Rougail repose sur le logiciel libre Tiramisu comme moteur de contrainte.
|
||||
|
||||
Rougail est composé :
|
||||
|
||||
- d'un format de description
|
||||
- d'un projet principal "Rougail" qui :
|
||||
|
||||
- charge les fichiers de structures,
|
||||
- applique les valeurs des données utilisateur,
|
||||
- représente les variables avec leurs valeurs.
|
||||
|
||||
- différents sous projet pour étendre les fonctionnalités de base
|
||||
- un outil en ligne de commande pour facilité l'utilisation de la bibliothèque.
|
||||
|
||||
|
||||
## Les acteurs
|
||||
|
||||
Rougail est destiné a séparer le cycle de vie de la variable entre 3 acteurs :
|
||||
|
||||
- l'acteur qui défini les variables
|
||||
- l'acteur qui adapte les valeurs
|
||||
- l'acteur qui utilise les variables avec leurs valeurs
|
||||
|
||||
Exemples concret d'acteur :
|
||||
|
||||
Dans le cadre du déploiement d'une configuration :
|
||||
|
||||
- l'intégrateur défini les variables
|
||||
- l'exploitant adapte les valeurs
|
||||
- l'installeur utilise les variables avec leurs valeurs
|
||||
|
||||
Dans le cadre du développement d'une application :
|
||||
|
||||
- le dévelopeur défini les variables
|
||||
- l'utilisateur adapte les valeurs
|
||||
- l'application utilise les variables avec leurs valeurs
|
||||
|
||||
|
||||
|------------------------------------------|
|
||||
| Acteur |
|
||||
|------------------------------------------|
|
||||
| défini les variables |
|
||||
| adapte les valeurs |
|
||||
| utilise les variables avec leurs valeurs |
|
||||
|------------------------------------------|
|
||||
|
||||
|
||||
## Cycle de vie des variables
|
||||
|
||||
Le but de Rougail est de gérer les variables et plus largement la configuration.
|
||||
|
||||
Rougail a pour but de définir les variables puis de gérer tout son cycle de vie.
|
||||
|
||||
Dans le cycle de vie d'une variable, on inclut les étapes générique d'une variable (par exemple pour le langage C) :
|
||||
|
||||
- déclaration (elles se voient attribuer un nom et un type) ;
|
||||
- définition (elles se voient affecter leur première valeur) ;
|
||||
- affectation (elles se voient modifier la valeur de la variable) ;
|
||||
- lecture (elles se voient utilisent la valeur de la variable) ;
|
||||
- fin de vie (elles se terminent à la destruction de l'objet).
|
||||
|
||||
Mais d'autres notions sont inclusent dans le cycle de vie :
|
||||
|
||||
- extension de la déclaration
|
||||
|
||||
- la "description" de la variable
|
||||
- présentation, l'acteur qui adapte les valeurs doit avoir toutes les informations nécessaires pour renseigner les valeurs, c'est ainsi qu'il est possible de généré automatiquement la documentation, le journal des modifications, ...
|
||||
|
||||
- autorisations, des propriétés décrivent les contraintes d'accès
|
||||
- spécialisation, qui décrit l'usage possible d'une variable
|
||||
|
||||
Rôle des différents composants Rougail :
|
||||
|
||||
Le format permet de décrire :
|
||||
|
||||
- la déclaration (nom, type, description, la présentation)
|
||||
- les autorisations
|
||||
- la spécialisation
|
||||
|
||||
Rougail et ces composants :
|
||||
|
||||
- la déclaration (via Tiramisu)
|
||||
- la présentation
|
||||
- l'affectation (via Tiramisu)
|
||||
- la lecture
|
||||
- la fin de vie
|
||||
|
||||
|------------------------------------------|----------------------------|
|
||||
| Acteur | Cycle de vies |
|
||||
|------------------------------------------|----------------------------|
|
||||
| défini les variables | déclaration + présentation |
|
||||
| adapte les valeurs | affectration |
|
||||
| utilise les variables avec leurs valeurs | lecture |
|
||||
| | destruction |
|
||||
|------------------------------------------|----------------------------|
|
||||
|
||||
|
||||
## Architecture Structurals-UserDatas-Outputs
|
||||
|
||||
|
||||
### Structurals
|
||||
|
||||
Les fichiers de "Structures" sont des fichiers au format Rougail dans laquelle toutes les informations du cycle de vie sont définies.
|
||||
|
||||
Avoir des données structurées veut dire qu'on peut publier une fois et avoir plusieurs rendus.
|
||||
|
||||
Il est important de tout mettre ces informations au même endroit. Ainsi on connaitre toutes les aspects de la variable en lisant ces fichiers.
|
||||
On y retrouve :
|
||||
|
||||
- un schéma
|
||||
- la définition des contraintes
|
||||
- des éléments de documentation
|
||||
- ...
|
||||
|
||||
Les variables sont ici mutables, elles peuvent être redéfinit à tout moment.
|
||||
Ces fichiers sont créées par l'acteur qui défini les variables.
|
||||
|
||||
|
||||
### UserDatas
|
||||
|
||||
Une fois la structure définie, il est possible de charger les "Données Utilisateur" (UserDatas). On retrouve plusieurs type de données utilisateurs :
|
||||
|
||||
- des fichiers de configuration
|
||||
- des variables d'environnement
|
||||
- des sources externes
|
||||
- des options de lignes de commande
|
||||
- un formulaire
|
||||
- ...
|
||||
|
||||
Les variables sont ici immuables, par contre les valeurs sont mutables.
|
||||
Ces sources sont peuplées par l'acteur qui adapte les valeurs.
|
||||
|
||||
|
||||
### Outputs
|
||||
|
||||
Ensuite on pourra définir sous quelle forme on veut recueillir l'information (Outputs) :
|
||||
|
||||
- un objet Tiramisu
|
||||
- une extraction JSON
|
||||
- un export pour l'inventaire Ansible
|
||||
- de la documetation
|
||||
- ...
|
||||
|
||||
Les variables et les valeurs sont ici immuables.
|
||||
|
||||
Voici un exemple concret :
|
||||
|
||||
Un intégrateur a besoin d'une variable et défini la défini ainsi (dans le fichier `structure_architecture.yml`) :
|
||||
|
||||
```yaml
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable:
|
||||
...
|
||||
```
|
||||
|
||||
L'exploitant défini la valeur de cette variable ainsi (dans le fichier `userdata.yml`) :
|
||||
|
||||
```yaml
|
||||
---
|
||||
my_variable: a value
|
||||
```
|
||||
|
||||
On désire afficher de manière lisible la configuration :
|
||||
|
||||
```bash
|
||||
rougail -m structure_architecture.yml -u yaml -yf userdata.yml
|
||||
╭──────── Caption ────────╮
|
||||
│ Variable Modified value │
|
||||
╰─────────────────────────╯
|
||||
Variables:
|
||||
┗━━ 📓 my_variable: a value ◀ loaded from the YAML file "userdata.yml"
|
||||
```
|
||||
|
||||
|-------------|------------------------------------------|----------------------------|----------|----------|
|
||||
| Étape | Acteur | Cycle de vies | Variable | Valeur |
|
||||
|-------------|------------------------------------------|----------------------------|----------|----------|
|
||||
| Structurals | défini les variables | déclaration + présentation | mutable | |
|
||||
| UserDatas | adapte les valeurs | affectration | immuable | mutable |
|
||||
| Outputs | utilise les variables avec leurs valeurs | lecture | immuable | immuable |
|
||||
| | | destruction | | |
|
||||
|-------------|------------------------------------------|----------------------------|----------|----------|
|
||||
|
||||
|
||||
### Valeur par défaut
|
||||
|
||||
Les variables ont une valeur. Une valeur par défaut est définit à la variable (None ou []) mais il est possible d'en définir une autre.
|
||||
|
||||
Il ne faut pas confondre la valeur par défaut ou la/les valeur(s) défini par l'acteur adaptant la configuration.
|
||||
|
||||
Par exemple, si je veux définir la variable my_variable en y spécifiant une valeur par défaut (dans le fichier `structure_default.yml`) :
|
||||
|
||||
```yaml
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable:
|
||||
default: a default value
|
||||
...
|
||||
```
|
||||
|
||||
```bash
|
||||
rougail -m structure_default.yml
|
||||
╭─────── Caption ────────╮
|
||||
│ Variable Default value │
|
||||
╰────────────────────────╯
|
||||
Variables:
|
||||
┗━━ 📓 my_variable: a default value
|
||||
```
|
||||
|
||||
|-------------|------------------------------------------|----------------------------|----------|----------|
|
||||
| Étape | Acteur | Cycle de vies | Variable | Valeur |
|
||||
|-------------|------------------------------------------|----------------------------|----------|----------|
|
||||
| Structurals | défini les variables | déclaration + présentation | mutable | défaut |
|
||||
| UserDatas | adapte les valeurs | affectration | immuable | mutable |
|
||||
| Outputs | utilise les variables avec leurs valeurs | lecture | immuable | immuable |
|
||||
| | | destruction | | |
|
||||
|-------------|------------------------------------------|----------------------------|----------|----------|
|
||||
|
||||
|
||||
## Le format : un langage
|
||||
|
||||
|
||||
### DSL (Domain Specific Language)
|
||||
|
||||
Contrairement à un langage générique, un langage dédié est conçu pour répondre à un domaine d'application précis.
|
||||
|
||||
La description des variables se faire dans des fichiers YAML version 1.2. Le langage de configuration de Rougail permet de décrire tout le cycle de vie de la variable.
|
||||
|
||||
|
||||
### Abstraction déclarative
|
||||
|
||||
Les variables sont décrite suivant un modèle déclaratif. Cela signigie que l'utilisateur définit simplement l'état final souhaité de celle-ci. Tiramisu determinera les actions nécessaires pour atteindre cet état.
|
||||
|
||||
Dit autrement l'utilisateur défini le schéma des variables qui sera ensuite appliqué de manière déterministe.
|
||||
|
||||
|
||||
|
||||
### Redéfinition explicite
|
||||
|
||||
Les variables peuvent être redéfinis à tout moment (utile notamment lorsqu'on définit des modèles de configuration). Mais la redéfinition d'une variable doit être explicitement déclaré comme tel.
|
||||
|
||||
Par exemple, si je veux redéfinir la variable my_variable en y spécifiant une valeur par défaut (dans le fichier `structure_redefine.yml`) :
|
||||
|
||||
```yaml
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable:
|
||||
redefine: true
|
||||
default: a new default value
|
||||
...
|
||||
```
|
||||
|
||||
```bash
|
||||
rougail -m structure_default.yml structure_redefine.yml
|
||||
╭─────── Caption ────────╮
|
||||
│ Variable Default value │
|
||||
╰────────────────────────╯
|
||||
Variables:
|
||||
┗━━ 📓 my_variable: a new default value
|
||||
```
|
||||
|
||||
|
||||
## Typage
|
||||
|
||||
|
||||
### Type standard
|
||||
|
||||
Rougail (et Tiramisu) accepte les types standards suivant :
|
||||
|
||||
- string (type par défaut d'une variable)
|
||||
- integer
|
||||
- float
|
||||
- boolean
|
||||
|
||||
|
||||
### Type métier
|
||||
|
||||
Mais on va retrouver également tout une série de type métier :
|
||||
|
||||
- IP
|
||||
- domainname
|
||||
- port
|
||||
- MAC
|
||||
- choice
|
||||
- secret
|
||||
- ...
|
||||
|
||||
Voici quelques exemples (dans le fichier `structure_type.yml`) :
|
||||
|
||||
```yaml
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_integer: 1
|
||||
|
||||
my_mail:
|
||||
type: mail
|
||||
default: foo@bar.net
|
||||
|
||||
my_date:
|
||||
type: date
|
||||
default: "2025-11-19"
|
||||
...
|
||||
```
|
||||
|
||||
```bash
|
||||
rougail -m structure_type.yml
|
||||
╭─────── Caption ────────╮
|
||||
│ Variable Default value │
|
||||
╰────────────────────────╯
|
||||
Variables:
|
||||
┣━━ 📓 my_integer: 1
|
||||
┣━━ 📓 my_mail: foo@bar.net
|
||||
┗━━ 📓 my_date: 2025-11-19
|
||||
```
|
||||
|
||||
|
||||
### Fortement typé
|
||||
|
||||
Rougail utilise en interne la bibliothèque Tiramisu. Les variables dans Tiramisu sont fortement typé.
|
||||
C'est à dire que le chargement des données utilisateur implique une attention sur le type des variables. Pour les données utilisateurs non typées (comme les variables d'environnement), en pré traitement, il y aura une adaptation du type de la valeur.
|
||||
|
||||
Par exemple si l'exploitant adapte la valeur de cette variable ainsi (dans le fichier userdata_fort_type.yml :
|
||||
|
||||
```yaml
|
||||
---
|
||||
my_variable: 1
|
||||
```
|
||||
|
||||
La valeur ne pourra pas être chargée (le type par défaut étant le type "string") :
|
||||
|
||||
```bash
|
||||
rougail -m structure_architecture.yml -u yaml -yf userdata_fort_type.yml
|
||||
🔔 WARNINGS
|
||||
┗━━ the value "1" is an invalid string for "my_variable", which is not a string, it will be ignored when loading from the YAML file "userdata.yml"
|
||||
🛑 ERRORS
|
||||
┗━━ The following variables are mandatory but have no value:
|
||||
┗━━ my_variable
|
||||
```
|
||||
|
||||
### Typage dynamique
|
||||
|
||||
Au moment de la définition de la structure, le type est dynamique. C'est à dire que l'acteur qui défini la variable peut changé à tout moment le type de la variable.
|
||||
|
||||
Par exemple (dans le fichier `structure_redefine_type.yml`) :
|
||||
|
||||
```yaml
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable:
|
||||
redefine: true
|
||||
type: integer
|
||||
...
|
||||
```
|
||||
|
||||
```bash
|
||||
rougail -m structure_architecture.yml structure_redefine_type.yml -u yaml -yf userdata_fort_type.yml
|
||||
╭──────── Caption ────────╮
|
||||
│ Variable Modified value │
|
||||
╰─────────────────────────╯
|
||||
Variables:
|
||||
┗━━ 📓 my_variable: 1 ◀ loaded from the YAML file "userdata.yml"
|
||||
```
|
||||
|
||||
Par contre, comme l'exemple du typage fort le suggère, l'acteur qui adapte la valeur n'a pas la possiblité de redéfinir le type de la variable.
|
||||
|
||||
### Inférence de type
|
||||
|
||||
Le type peut être défini explicitement (comme dans le fichier structure_type.yml) ou déduit du typage des variables YAML.
|
||||
|
||||
Par exemple la variable avec une valeur par défaut à 1 est une variable de type "integer" (a mettre dans le fichier `structure_inference.yml`) :
|
||||
|
||||
```yaml
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable: 1
|
||||
...
|
||||
```
|
||||
|
||||
```bash
|
||||
rougail -m structure_inference.yml
|
||||
╭─────── Caption ────────╮
|
||||
│ Variable Default value │
|
||||
╰────────────────────────╯
|
||||
Variables:
|
||||
┗━━ 📓 my_variable: 1
|
||||
```
|
||||
|
||||
|
||||
### Variable "nullable"
|
||||
|
||||
Le type "null" (ou "None" en python) n'existe pas dans Rougail. "null" est une valeur. Tous les types peuvent accepter cette valeur, mais par défaut, ce n'est pas le cas.
|
||||
|
||||
Voici la déclaration d'une variable avec la valeur par défaut à "null" (dans le fichier `structure_nullable.yml`) :
|
||||
|
||||
```yaml
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable:
|
||||
...
|
||||
```
|
||||
|
||||
```bash
|
||||
rougail -m structure_nullable.yml
|
||||
🛑 ERRORS
|
||||
┗━━ The following variables are mandatory but have no value:
|
||||
┗━━ my_variable
|
||||
```
|
||||
|
||||
En réalité la variable n'est pas accessible lorsque Tiramisu est mode "lecture seule" (ce qui est le cas lors des étapes Outputs par défaut). Lorsqu'on force le mode "lecture écriture" on a bien accès :
|
||||
|
||||
```bash
|
||||
rougail -m structure_nullable.yml --cli.read_write
|
||||
╭─────── Caption ────────╮
|
||||
│ Variable Default value │
|
||||
╰────────────────────────╯
|
||||
Variables:
|
||||
┗━━ 📓 my_variable: null
|
||||
```
|
||||
|
||||
Pour que notre variable accepte dans tous les cas "null" il faut modifier le fichier de structure comme cela :
|
||||
|
||||
```yaml
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable:
|
||||
mandatory: false
|
||||
...
|
||||
```
|
||||
|
||||
```bash
|
||||
rougail -m structure_nullable.yml --cli.read_write
|
||||
╭─────── Caption ────────╮
|
||||
│ Variable Default value │
|
||||
╰────────────────────────╯
|
||||
Variables:
|
||||
┗━━ 📓 my_variable: null
|
||||
```
|
||||
|
||||
|
||||
### Variable "liste"
|
||||
|
||||
La liste n'est pas non plus un type. C'est une propriété d'une variable. Cela signifie qu'une liste ne peut pas contenir des valeurs de plusieurs types.
|
||||
|
||||
|
||||
### Famille objet
|
||||
|
||||
Une famille est une variable d'un type particuiler. C'est un conteneur destiné à accueillir des variables.
|
||||
|
||||
|
||||
#### Un objet
|
||||
|
||||
Ce qu'on appele "objet" généralement est appeler dans Rougail des "familles". Donc au lieu de déclarer mes variables à la racine, je vais la déclarer dans une famille.
|
||||
|
||||
Par exemple dans le fichier `structure_family.yml` je créé un famille my_object qui contient deux variables :
|
||||
|
||||
```yaml
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_object:
|
||||
|
||||
key1: value1
|
||||
|
||||
key2: value2
|
||||
...
|
||||
```
|
||||
|
||||
Si j'exporte au format JSON j'ai bien un objet :
|
||||
|
||||
```bash
|
||||
rougail -m structure_family.yml -o json
|
||||
{
|
||||
"my_object": {
|
||||
"key1": "value1",
|
||||
"key2": "value2"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Les familles gèrent l'arborescence. Il est possible de faire des sous-familles.
|
||||
|
||||
|
||||
#### Liste d'objet
|
||||
|
||||
Une famille particulière, appeler "leadership" permet d'avoir une liste d'objet identique.
|
||||
|
||||
Par exemple si je veux pouvoir créer un nombre non limité d'utilisateur associé à un mot de passe, je ne peux pas passer par des listes, je veux une liste d'objet.
|
||||
|
||||
Voici le contenu du fichier `structure_leadership.yml` :
|
||||
|
||||
```yaml
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
users:
|
||||
type: leadership
|
||||
|
||||
username:
|
||||
type: unix_user
|
||||
|
||||
password:
|
||||
type: secret
|
||||
...
|
||||
```
|
||||
|
||||
Et le fichier `userdata_leadership.yml` :
|
||||
|
||||
```yaml
|
||||
---
|
||||
users:
|
||||
- username: foo
|
||||
password: SoSecr31
|
||||
- username: bar
|
||||
password: SoSecr31
|
||||
- username: toot
|
||||
password: SoSecr31
|
||||
...
|
||||
```
|
||||
|
||||
J'ai bien une liste d'objet :
|
||||
|
||||
```bash
|
||||
rougail -m structure_leadership.yml -u yaml -yf userdata_leadership.yml -o json
|
||||
{
|
||||
"users": [
|
||||
{
|
||||
"username": "foo",
|
||||
"password": "SoSecr31"
|
||||
},
|
||||
{
|
||||
"username": "bar",
|
||||
"password": "SoSecr31"
|
||||
},
|
||||
{
|
||||
"username": "toot",
|
||||
"password": "SoSecr31"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|-------------|------------------------------------------|----------------------------|----------|----------|------------|
|
||||
| Étape | Acteur | Cycle de vies | Variable | Valeur | Propriétés |
|
||||
|-------------|------------------------------------------|----------------------------|----------|----------|------------|
|
||||
| Structurals | défini les variables | déclaration + présentation | mutable | défaut | |
|
||||
| UserDatas | adapte les valeurs | affectration | immuable | mutable | |
|
||||
| Outputs | utilise les variables avec leurs valeurs | lecture | immuable | immuable | mandatory |
|
||||
| | | destruction | | | |
|
||||
|-------------|------------------------------------------|----------------------------|----------|----------|------------|
|
||||
|
||||
|
||||
## Intégrité des données
|
||||
|
||||
L'intégrité des données fait référence au fait que les données doivent être fiables et précises tout au long de leur cycle de vie.
|
||||
|
||||
Cela signifie que la valeur doit être :
|
||||
|
||||
- de qualité
|
||||
- adapté au context globale
|
||||
|
||||
|
||||
### Qualité de la donnée
|
||||
|
||||
Pour avoir des données de qualité, il faut que l'outil valide la saisie utilisateur.
|
||||
|
||||
La première façon de valider la donnée est bien évidement de définir le bon type.
|
||||
|
||||
Mais cela ne suffit pas.
|
||||
|
||||
#### Paramètres de type
|
||||
|
||||
Il existe, pour certains type, un certains nombres de paramètres qui vont pouvoir compléter le typage des variables (dans le fichier `structure_param_type.yml`) :
|
||||
|
||||
```yaml
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_percent:
|
||||
type: integer
|
||||
params:
|
||||
min_integer: 0
|
||||
max_integer: 100
|
||||
default:
|
||||
10
|
||||
...
|
||||
```
|
||||
|
||||
```bash
|
||||
rougail -m structure_param_type.yml
|
||||
╭─────── Caption ────────╮
|
||||
│ Variable Default value │
|
||||
╰────────────────────────╯
|
||||
Variables:
|
||||
┗━━ 📓 my_percent: 10
|
||||
```
|
||||
|
||||
Mais avec une donnée utilisateur invalide, la valeur ne sera pas chargé (dans le fichier `userdata1.yml`) :
|
||||
|
||||
```yaml
|
||||
---
|
||||
my_percent: 120
|
||||
```
|
||||
|
||||
```bash
|
||||
rougail -m structure6.yml -u yaml -yf userdata1.yml
|
||||
🔔 WARNINGS
|
||||
┗━━ the value "120" is an invalid integer for "my_percent", value must be less than "100", it will be
|
||||
ignored when loading from the YAML file "userdata1.yml"
|
||||
╭─────── Caption ────────╮
|
||||
│ Variable Default value │
|
||||
╰────────────────────────╯
|
||||
Variables:
|
||||
┗━━ 📓 my_percent: 10
|
||||
```
|
||||
|
||||
Ou pourra même généré une erreur :
|
||||
|
||||
```bash
|
||||
rougail -m structure6.yml -u yaml -yf userdata1.yml --cli.invalid_user_datas_error
|
||||
🛑 ERRORS
|
||||
┗━━ the value "120" is an invalid integer for "my_percent", value must be less than "100", it will be
|
||||
ignored when loading from the YAML file "userdata1.yml
|
||||
```
|
||||
|
||||
|
||||
#### Validation
|
||||
|
||||
Mais il est possible d'ajouter des validations complémentaires, par exemple ici vérifier que la variable est impaire (dans le fichier `structure_validators.yml`) :
|
||||
|
||||
```yaml
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_odd_variable:
|
||||
type: integer
|
||||
validators:
|
||||
- jinja: "{% if not (_.my_odd_variable % 2) %}not an odd integer{% endif %}"
|
||||
default:
|
||||
10
|
||||
...
|
||||
```
|
||||
|
||||
```bash
|
||||
rougail -m structure7.yml
|
||||
🛑 ERRORS
|
||||
┗━━ "10" is an invalid integer for "my_odd_variable", not an odd integer
|
||||
```
|
||||
|
||||
Par contre cela passe avec une valeur impaire (dans le fichier `userdata_validators.yml`) :
|
||||
|
||||
```yaml
|
||||
---
|
||||
my_odd_variable: 11
|
||||
```
|
||||
|
||||
|
||||
```bash
|
||||
rougail -m structure_validators.yml -u yaml -yf userdata_validators.yml
|
||||
╭────────────── Caption ───────────────╮
|
||||
│ Variable Modified value │
|
||||
│ (⏳ Original default value) │
|
||||
╰──────────────────────────────────────╯
|
||||
Variables:
|
||||
┗━━ 📓 my_odd_variable: 11 ◀ loaded from the YAML file "userdata_validators.yml" (⏳ 10)
|
||||
```
|
||||
|
||||
### Cohérence globale
|
||||
|
||||
Une variable isolée peut être considéré comme étant de qualité mais devenir incohérence suivant le contexte.
|
||||
|
||||
Par exemple, si on demande une valeur minimum puis une valeur maximum, la minimal doit être inférieur à la maximal. Dans le fichier `structure_consistency.yml` on a :
|
||||
|
||||
```yaml
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_min_value: 11
|
||||
|
||||
my_max_value:
|
||||
default:
|
||||
variable: _.my_min_value
|
||||
validators:
|
||||
- jinja: |-
|
||||
{% if _.my_min_value >= _.my_max_value %}
|
||||
must but upper than {{ _.my_min_value }} (the value of "my_min_value")
|
||||
{% endif %}
|
||||
...
|
||||
```
|
||||
|
||||
```bash
|
||||
rougail -m structure_consistency.yml
|
||||
🛑 ERRORS
|
||||
┗━━ "11" is an invalid integer for "my_max_value", must but upper than 11 (the value of "my_min_value")
|
||||
```
|
||||
|
||||
Si on défini la bonne valeur :
|
||||
|
||||
```yaml
|
||||
---
|
||||
my_max_value: 13
|
||||
```
|
||||
|
||||
```bash
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_min_value: 11
|
||||
|
||||
my_max_value:
|
||||
default:
|
||||
variable: _.my_min_value
|
||||
validators:
|
||||
- jinja: |-
|
||||
{% if _.my_min_value >= _.my_max_value %}
|
||||
must but upper than {{ _.my_min_value }} (the value of "my_min_value")
|
||||
{% endif %}
|
||||
...
|
||||
```
|
||||
|
||||
```bash
|
||||
rougail -m structure_consistency.yml -u yaml -yf userdata_consistency.yml
|
||||
╭────────────── Caption ───────────────╮
|
||||
│ Variable Default value │
|
||||
│ Modified value │
|
||||
│ (⏳ Original default value) │
|
||||
╰──────────────────────────────────────╯
|
||||
Variables:
|
||||
┣━━ 📓 my_min_value: 11
|
||||
┗━━ 📓 my_max_value: 13 ◀ loaded from the YAML file "userdata_consistency.yml" (⏳ 11)
|
||||
```
|
||||
|
||||
|
||||
## Contrôle des accès
|
||||
|
||||
Le contrôle des accès est réalisé dès qu'on essaye d'accéder à une variable.
|
||||
|
||||
Dans Tiramisu il existe deux modes d'accès aux variables par défaut :
|
||||
|
||||
- le mode "lecture écriture" : ce mode est utilisé au moment du chargement des données utilisateurs
|
||||
- le mode "lecture seule" : ce mode est utilisé au moment de le représentation des valeurs
|
||||
|
||||
Il existe deux grands type de contrôle des accès :
|
||||
|
||||
- les modes
|
||||
- les propriétés
|
||||
|
||||
On pourrait rajouter les étiquettes à cette liste, même si l'objectif n'est pas spécialement de contrôler les accès via les étiquettes.
|
||||
|
||||
|
||||
### Les modes
|
||||
|
||||
On va partir sur un cas classic de définition des modes. On part sur trois mode :
|
||||
|
||||
- basic : de façon automatique les variables obligatoires sans valeur par défaut (dans ce cas l'acteur qui adapte la configuration devra obligatoirement renseigné des valeurs) et manuellement les variables que l'acteur qui définit les variables juge utile
|
||||
- standard : automatique les autres variables
|
||||
- advanced : les variables que l'acteur qui définit les variables décide de mettre
|
||||
|
||||
Par exemple créons deux variables dans `structure_mode.yml` avec des modes différents :
|
||||
|
||||
```yaml
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
standard_variable: default value
|
||||
|
||||
advanced_variable:
|
||||
mode: advanced
|
||||
default: default value
|
||||
...
|
||||
```
|
||||
|
||||
Avec le fichier `userdata_mode.yml` :
|
||||
|
||||
```yaml
|
||||
---
|
||||
standard_variable: value
|
||||
|
||||
advanced_variable: value
|
||||
```
|
||||
|
||||
```yaml
|
||||
rougail -m structure_mode.yml -u yaml -ff userdata_mode.yml --modes_level basic standard advanced
|
||||
╭────────────── Caption ───────────────╮
|
||||
│ Variable Modified value │
|
||||
│ (⏳ Original default value) │
|
||||
╰──────────────────────────────────────╯
|
||||
Variables:
|
||||
┣━━ 📓 standard_variable: value ◀ loaded from the YAML file "userdata_mode.yml" (⏳ default value)
|
||||
┗━━ 📓 advanced_variable: value ◀ loaded from the YAML file "userdata_mode.yml" (⏳ default value)
|
||||
```
|
||||
|
||||
Et interdisont aux acteurs adaptant la configuration de modifier les variables "advanced" :
|
||||
|
||||
```bash
|
||||
rougail -m structure_mode.yml -u yaml -yf userdata_mode.yml --modes_level basic standard advanced --cli.inaccessible_read_write_modes advanced
|
||||
🔔 WARNINGS
|
||||
┗━━ variable "advanced_variable" is advanced, it will be ignored when loading from the YAML file "userdata_mode.yml"
|
||||
╭───────────────────── Caption ─────────────────────╮
|
||||
│ Variable Default value │
|
||||
│ Undocumented variable Modified value │
|
||||
│ (⏳ Original default value) │
|
||||
╰───────────────────────────────────────────────────╯
|
||||
Variables:
|
||||
┣━━ 📓 standard_variable: value ◀ loaded from the YAML file "userdata_mode.yml" (⏳ default value)
|
||||
┗━━ 📓 advanced_variable: default value
|
||||
```
|
||||
|
||||
La gestion des modes est plutôt limités via la ligne de commande. Pour des besoins plus spécifique il sera nécessaire de passer par la bibliothèque.
|
||||
|
||||
|
||||
### Les propriétés
|
||||
|
||||
Les deux propriétés importantes sont :
|
||||
|
||||
- les variables cachée
|
||||
- les variables désactivée
|
||||
|
||||
Ces propriétés peuvent être fixe ou calculer suivant le contexte
|
||||
|
||||
|
||||
#### Variable cachée
|
||||
|
||||
Une variable cachée est une variable qui ne sera pas modifiable par l'utilisateur et que ne sera pas présente en mode "lecture écriture" mais présente en mode "lecture seule".
|
||||
|
||||
Généralement on utilise ce type de variable lorsqu'on ne veut pas que l'acteur qui adapte la configuration puisse modifier cette variable ou alors parce que la valeur de la variable est issu d'un calcul.
|
||||
|
||||
|
||||
#### Variable désactivée
|
||||
|
||||
Une variable désactiver est une variable qui sera accessible a aucun des acteurs.
|
||||
|
||||
On utilise généralement cette propriété de façon dynamique pour supprimer l'accès à cette variable suivant le context.
|
||||
|
||||
Prenons un exemple de variable cachée (donc non modifiable) et ajoutons un variable "use_proxy" qui permet de définir une adresse proxy si on le souhait. Pour cela nous allons créer le fichier suivante : `structure_properties.yml` :
|
||||
|
||||
```yaml
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
hidden_variable:
|
||||
hidden: true
|
||||
default: accessible
|
||||
|
||||
use_proxy: false
|
||||
|
||||
proxy_address:
|
||||
disabled:
|
||||
variable: use_proxy
|
||||
when: false
|
||||
...
|
||||
```
|
||||
|
||||
```bash
|
||||
rougail -m structure_properties.yml
|
||||
╭────────────── Caption ──────────────╮
|
||||
│ Variable Default value │
|
||||
│ Unmodifiable variable │
|
||||
╰─────────────────────────────────────╯
|
||||
Variables:
|
||||
┣━━ 📓 hidden_variable: accessible
|
||||
┗━━ 📓 use_proxy: false
|
||||
```
|
||||
|
||||
Essayons de modifier la variable cachée et de configurer le proxy dans le fichier `userdata_properties.yml` :
|
||||
|
||||
```yaml
|
||||
---
|
||||
hidden_variable: inaccessible
|
||||
|
||||
use_proxy: true
|
||||
|
||||
proxy_address: https://proxy.foo.net:4128/
|
||||
```
|
||||
|
||||
```yaml
|
||||
rougail -m structure_properties.yml -u yaml -ff userdata_properties.yml
|
||||
🔔 WARNINGS
|
||||
┗━━ variable "hidden_variable" is hidden, it will be ignored when loading from the YAML file "userdata_properties.yml"
|
||||
╭───────────────────── Caption ─────────────────────╮
|
||||
│ Variable Default value │
|
||||
│ Unmodifiable variable Modified value │
|
||||
│ (⏳ Original default value) │
|
||||
╰───────────────────────────────────────────────────╯
|
||||
Variables:
|
||||
┣━━ 📓 hidden_variable: accessible
|
||||
┣━━ 📓 use_proxy: true ◀ loaded from the YAML file "userdata_properties.yml" (⏳ false)
|
||||
┗━━ 📓 proxy_address: https://proxy.foo.net:4128/ ◀ loaded from the YAML file "userdata_properties.yml"
|
||||
```
|
||||
|
||||
|-------------|------------------------------------------|----------------------------|----------|----------|--------------------|----------------------|
|
||||
| Étape | Acteur | Cycle de vies | Variable | Valeur | Lecture | Écriture | Propriétés |
|
||||
|-------------|------------------------------------------|----------------------------|----------|----------|--------------------|----------------------|
|
||||
| Structurals | défini les variables | déclaration + présentation | mutable | défaut | | |
|
||||
| UserDatas | adapte les valeurs | affectration | immuable | mutable | lecture + écriture | hidden + disabled |
|
||||
| Outputs | utilise les variables avec leurs valeurs | lecture | immuable | immuable | lecture | disabled + mandatory |
|
||||
| | | destruction | | | | |
|
||||
|-------------|------------------------------------------|----------------------------|----------|----------|--------------------|----------------------|
|
||||
2
docs/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
.venv/
|
||||
build/
|
||||
20
docs/Makefile
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line, and also
|
||||
# from the environment for the first two.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
3
docs/_static/css/custom.css
vendored
|
|
@ -1,4 +1,7 @@
|
|||
.wy-table-responsive table td {
|
||||
white-space: normal;
|
||||
}
|
||||
.underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
|
|
|
|||
73
docs/_static/terminal.css
vendored
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
.terminal {
|
||||
background-color: #000000; /* Fond noir */
|
||||
color: #00ff00; /* Texte vert, typique des anciens terminaux */
|
||||
font-family: 'Courier New', Courier, monospace; /* Police à chasse fixe */
|
||||
padding: 5px; /* Espace réduit autour du texte */
|
||||
border-radius: 5px;
|
||||
border: 1px solid #00ff00; /* Bordure verte */
|
||||
white-space: pre-wrap;
|
||||
overflow-x: auto; /* Défilement horizontal si nécessaire */
|
||||
box-shadow: 0 0 10px rgba(0, 255, 0, 0.5); /* Ombre verte pour un effet rétro */
|
||||
display: flex; /* Active Flexbox */
|
||||
line-height: 1.2; /* Espacement entre les lignes */
|
||||
display: inline-block; /* Pour que le fond s'adapte au contenu */
|
||||
width: 100%; /* Largeur maximale */
|
||||
}
|
||||
|
||||
.terminal,
|
||||
.terminal * {
|
||||
border: none !important; /* Supprime toutes les bordures à l'intérieur du terminal */
|
||||
}
|
||||
|
||||
.terminal .highlight {
|
||||
margin: 0; /* Supprime les marges */
|
||||
padding: 0; /* Supprime les paddings */
|
||||
background-color: transparent; /* Fond transparent pour éviter les conflits */
|
||||
}
|
||||
|
||||
.terminal .highlight pre {
|
||||
margin: 0; /* Supprime les marges */
|
||||
padding: 0; /* Supprime les paddings */
|
||||
background-color: transparent; /* Fond transparent */
|
||||
color: inherit; /* Hérite la couleur du texte du parent */
|
||||
font-family: inherit; /* Hérite la police du parent */
|
||||
line-height: inherit; /* Hérite l'espacement des lignes du parent */
|
||||
}
|
||||
|
||||
.terminal .highlight pre span {
|
||||
display: inline; /* Évite les espaces inutiles causés par inline-block */
|
||||
margin: 0; /* Supprime les marges */
|
||||
padding: 0; /* Supprime les paddings */
|
||||
}
|
||||
|
||||
.terminal .go {
|
||||
color: #00ff00; /* Couleur pour le texte de sortie du terminal */
|
||||
}
|
||||
|
||||
/* raw html output css */
|
||||
|
||||
/* Styles communs pour les deux classes */
|
||||
.error-box, .output {
|
||||
padding: 10px; /* Espace intérieur */
|
||||
font-size: 0.8em; /* Taille de police plus petite */
|
||||
width: fit-content; /* Ajuste la largeur au contenu */
|
||||
border-radius: 5px; /* Coins arrondis */
|
||||
display: inline-block; /* Pour que la boîte s'ajuste au contenu */
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.error-box pre, .output pre {
|
||||
margin: 0; /* Supprime la marge par défaut du <pre> */
|
||||
}
|
||||
|
||||
/* Styles spécifiques à la classe error-box */
|
||||
.error-box {
|
||||
border: 2px solid #ff0000; /* Bordure rouge */
|
||||
background-color: #ffe6e6; /* Fond légèrement rouge */
|
||||
}
|
||||
|
||||
/* Styles spécifiques à la classe output */
|
||||
.output {
|
||||
border: 2px solid #00ff00; /* Bordure verte */
|
||||
background-color: #e6ffe6; /* Fond légèrement vert */
|
||||
}
|
||||
344
docs/abstract.rst
Normal file
|
|
@ -0,0 +1,344 @@
|
|||
Abstract presentation
|
||||
=========================
|
||||
|
||||
Rougail is a robust and powerful, free/open-source configuration manager.
|
||||
|
||||
Rougail is:
|
||||
|
||||
- a CLI (command line interface) utility
|
||||
- a `Python <https://www.python.org/>`_ library
|
||||
- a YAML based description language
|
||||
|
||||
The language combines declaration, data validation, and templating in a single, declarative syntax.
|
||||
|
||||
It will be useful to:
|
||||
|
||||
- define variables (the structure) easily and their constraints
|
||||
- loads those variables
|
||||
- generate variables documentation
|
||||
- loads variables' values
|
||||
- validate the variables and the overall consistency handling system
|
||||
- generate custom table views
|
||||
- export to different common format (YAML, Ansible, ...)
|
||||
- ...
|
||||
|
||||
Why another configuration manager?
|
||||
-------------------------------------
|
||||
|
||||
Using Rougail tansforms end user consumer defined consistency rules into highly consistent business objects.
|
||||
It's a configuration language designed to simplify and unify the way you define,
|
||||
validate and generate configuration data.
|
||||
|
||||
In other word, making it easier to manage complex configurations across multiple environments.
|
||||
|
||||
You might tell me that other configuration management tools do the same thing. And that's partly true.
|
||||
|
||||
But Rougail adds interesting features in variable management that other projects don't have.
|
||||
We are of course referring to the documentation management included directly in the configuration manager.
|
||||
|
||||
Your configuration is therefore consistent, easily accessible, and modifiable.
|
||||
|
||||
Not to mention the always up-to-date documentation and the information you provide to your users regarding changes to variables.
|
||||
|
||||
What kind of configuration manager?
|
||||
---------------------------------------------
|
||||
|
||||
At the time of the design of Rougail, there were structuring choices
|
||||
that defined the functioning of the tool.
|
||||
|
||||
The steps in Rougail can be explained as follows:
|
||||
|
||||
- loading the variable's :term:`structured data`
|
||||
- loading the :term:`user data`
|
||||
- reading, validating, exporting, documenting (and so on...) the data
|
||||
|
||||
Structured data
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Structured data is also called the Rougail format.
|
||||
|
||||
.. glossary::
|
||||
|
||||
structured data
|
||||
|
||||
A variable-first :term:`DSL` (Domain-Specific Language) designed for describing variables, consistency
|
||||
and describe the relationships between variables in a declarative style.
|
||||
|
||||
The language is a mix of YAML and Jinja Templating.
|
||||
|
||||
It goes beyond traditional schema languages (like `JSON Schema <https://json-schema.org/>`_,
|
||||
`OpenAPI <https://www.openapis.org/>`_, `Cuelang <https://cuelang.org/>`_)
|
||||
by combinig type systems, powerful validation, consistency of the configuration and documentation.
|
||||
|
||||
Structured data are commonly placed in :term:`structure files <structure file>`.
|
||||
|
||||
User data
|
||||
~~~~~~~~~~
|
||||
|
||||
.. glossary::
|
||||
|
||||
user data
|
||||
|
||||
User data, as opposed to structured data, are data that only concern the assignment of values
|
||||
and not the consistency of the variables between them.
|
||||
|
||||
The variable's values are also called **user values**.
|
||||
|
||||
The consistency field is outside of the user data scope.
|
||||
The consistency is handled in the :term:`structured data <structured data>`\ 's scope.
|
||||
|
||||
Here a some user data examples:
|
||||
|
||||
- configuration files
|
||||
- environment variables
|
||||
- external sources
|
||||
- command-line options
|
||||
- a form
|
||||
|
||||
Output
|
||||
~~~~~~~
|
||||
|
||||
.. glossary::
|
||||
|
||||
output
|
||||
|
||||
Structured and user data form a coherent configuration useful for different purposes.
|
||||
|
||||
Output is here to define what kind of data we want.
|
||||
|
||||
Here are some output examples:
|
||||
|
||||
- :term:`Tiramisu` object
|
||||
- JSON extraction
|
||||
- Ansible inventory extraction
|
||||
- documentation
|
||||
- custom table views
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - **Step**
|
||||
|
||||
* - **Structured data**
|
||||
|
||||
* - **User data**
|
||||
|
||||
* - **Output**
|
||||
|
||||
.. _configuration:
|
||||
|
||||
Configuration
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
We've been talking about `configuration` for a while now. It's time to define what a configuration is.
|
||||
|
||||
.. glossary::
|
||||
|
||||
configuration
|
||||
|
||||
The configuration represents the set of variables and their values loaded in a tree-like fashion into memory from structural data, user data and any modifications during its lifecycle.
|
||||
|
||||
In practice, it's :term:`Tiramisu` who manages this part.
|
||||
|
||||
What kind of actor?
|
||||
---------------------
|
||||
|
||||
It's clear that Rougail can be used in many contexts.
|
||||
|
||||
Here we'll define actor names. Obviously, these aren't the only possible actors.
|
||||
|
||||
We're just defining the actors within the Rougail context.
|
||||
Choice your own actor name if you wish to personnalize in your specific context.
|
||||
|
||||
.. glossary::
|
||||
|
||||
integrator
|
||||
|
||||
An integrator in the Rougail field is the person who writes the :term:`structured <structured data>`\ .
|
||||
He has the responsibility of the integration process, that is,
|
||||
he defines the variables and the relationship between them, the variables that are allowed
|
||||
(or not) to be set, and so on. His responsabilites are the **structuration** and the **consistency**
|
||||
of the organisation of the variables between them.
|
||||
|
||||
.. glossary::
|
||||
|
||||
operator
|
||||
|
||||
An operator in the Rougail field is the person who assigns :term:`value`\ s to the pre-defined variables,
|
||||
his responsabilities are to set variable values correctly.
|
||||
|
||||
The user :term:`value`\ s, that is the values that have been set by the :term:`operator`, are of course type validated.
|
||||
The type validation is driven by the definitions in the :term:`structure file <structure file>`.
|
||||
|
||||
Here is a reminder of the different steps:
|
||||
|
||||
- the :term:`integrator` defines the structure
|
||||
- the :term:`operator` sets the value
|
||||
- the :term:`integrator` and/or the :term:`operator` use the output
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - **Step**
|
||||
- Actor
|
||||
|
||||
* - **Structured data**
|
||||
- Integrator
|
||||
|
||||
* - **User data**
|
||||
- Operator
|
||||
|
||||
* - **Output**
|
||||
- - Operator
|
||||
- Integrator
|
||||
|
||||
Variable lifecyle
|
||||
----------------------
|
||||
|
||||
Rougail's a configuration language and data validation tool is designed
|
||||
to simplify defining, validating, and generating structured configuration and data.
|
||||
|
||||
Rougail aims at defining variables.
|
||||
|
||||
Here we are talking about the variable lifecyle.
|
||||
|
||||
The variable’s lifecyle is the period between its creation and its destruction.
|
||||
|
||||
The lifecycle of a variable includes the generic stages (for example, like in the C language):
|
||||
|
||||
- Creation: variables are assigned a name and a type
|
||||
- Initialization: they are assigned their first value (we call it :term:`default value`)
|
||||
- Assignment: the variable's value is modified
|
||||
- Reading: the variable's value is used
|
||||
- Destruction: the variable terminates upon the destruction of the object
|
||||
|
||||
.. note:: No other concept is included in the lifecycle (ni particular the access control, with properties describing access constraints).
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - **Step**
|
||||
- Actor
|
||||
- Lifecyle
|
||||
|
||||
* - **Structured data**
|
||||
- Integrator
|
||||
- - Creation
|
||||
- Initialization
|
||||
|
||||
* - **User data**
|
||||
- Operator
|
||||
- - Access control
|
||||
- Reading
|
||||
- Assignment
|
||||
|
||||
* - **Output**
|
||||
- - Operator
|
||||
- Integrator
|
||||
- - Access control
|
||||
- Reading
|
||||
|
||||
.. _variable_mutability:
|
||||
|
||||
Variable mutability
|
||||
---------------------
|
||||
|
||||
.. _structured_data:
|
||||
|
||||
Structured data
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
When the :term:`integrator` defines the structure, variables are mutable.
|
||||
|
||||
Even if the default behavior is inconsistent, like when there is a conflict between multiple declarations for the same variable,
|
||||
|
||||
it's possible to explicitly allow to unify (combine) multiple variables declarations.
|
||||
|
||||
User data
|
||||
~~~~~~~~~~
|
||||
|
||||
At the user data level, it's no more possible to modify any variable definition.
|
||||
Here we are just talking about variable's values.
|
||||
|
||||
Output
|
||||
~~~~~~~
|
||||
|
||||
Variable definition settings are immutable.
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - **Step**
|
||||
- Actor
|
||||
- Lifecyle
|
||||
- Mutability
|
||||
|
||||
* - **Structured data**
|
||||
- Integrator
|
||||
- - Creation
|
||||
- Initialization
|
||||
- Mutable
|
||||
|
||||
* - **User data**
|
||||
- Operator
|
||||
- - Access control
|
||||
- Reading
|
||||
- Assignment
|
||||
- Immutable
|
||||
|
||||
* - **Output**
|
||||
- - Operator
|
||||
- Integrator
|
||||
- - Access control
|
||||
- Reading
|
||||
- Immutable
|
||||
|
||||
Value access
|
||||
-------------
|
||||
|
||||
In the :term:`structured data` step, there is no value, strictly speaking.
|
||||
The values set are default values.
|
||||
Like other parameters, the default value is explicitly mutable.
|
||||
|
||||
In the `user data` step, we can modify the values. That's precisely the purpose of this step.
|
||||
The configuration is said to be in :term:`read write mode`.
|
||||
|
||||
But at the `output` step, it is obviously no longer possible to modify the value.
|
||||
The configuration is said to be in :term:`read only mode`.
|
||||
|
||||
.. attention::
|
||||
It is important not to confuse `value` and `calculated value`.
|
||||
The result of a calculation can change over time.
|
||||
In this case, the value does indeed correspond to the result of the calculation.
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - **Step**
|
||||
- Actor
|
||||
- Lifecyle
|
||||
- Mutability
|
||||
- Value
|
||||
|
||||
* - **Structured data**
|
||||
- Integrator
|
||||
- - Creation
|
||||
- Initialization
|
||||
- Mutable
|
||||
- Mutable default value
|
||||
|
||||
* - **User data**
|
||||
- Operator
|
||||
- - Access control
|
||||
- Reading
|
||||
- Assignment
|
||||
- Immutable
|
||||
- Read write
|
||||
|
||||
* - **Output**
|
||||
- - Operator
|
||||
- Integrator
|
||||
- - Access control
|
||||
- Reading
|
||||
- Immutable
|
||||
- Read only
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
variable
|
||||
<https://en.wikipedia.org/wiki/Variable_(computer_science)>`_
|
||||
286
docs/check.rst
|
|
@ -1,286 +0,0 @@
|
|||
Verification function
|
||||
==========================
|
||||
|
||||
Synopsis
|
||||
-------------
|
||||
|
||||
A verification is a complementary validation to the type which allows the content of a variable to be validated more precisely.
|
||||
|
||||
A :term:`validator` is necessarily a Jinja type calculation.
|
||||
|
||||
Parameters
|
||||
--------------
|
||||
|
||||
Depending on the types of calculation, the parameters will be different:
|
||||
|
||||
.. list-table::
|
||||
:widths: 15 25 20 15
|
||||
:header-rows: 1
|
||||
|
||||
* - **Calculation type**
|
||||
- **Parameter**
|
||||
- **Comments**
|
||||
- **Sample**
|
||||
|
||||
* -
|
||||
- **type**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- Type of calculation, the only possible value is: jinja
|
||||
- jinja
|
||||
* - **jinja**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- Jinja template
|
||||
- {% if rougail.variable == 'not_allowed' %}not allowed!{% endif %}
|
||||
-
|
||||
* - **params**
|
||||
|
||||
`list`
|
||||
- Additional parameters passed to the Jinja template
|
||||
-
|
||||
-
|
||||
|
||||
There are two types of parameter:
|
||||
|
||||
- the standard parameters (string, boolean, integer, null), in this case just do: "key: value"
|
||||
- advanced settings:
|
||||
|
||||
- parameter via a variable
|
||||
- parameter via an information
|
||||
- parameter via a suffix: in the case of a variable in a dynamic family
|
||||
- parameter via an index: in the case of a :term:`follower` variable
|
||||
|
||||
.. list-table::
|
||||
:widths: 15 25 20 15
|
||||
:header-rows: 1
|
||||
|
||||
* - **Parameter's type**
|
||||
- **Parameter**
|
||||
- **Comments**
|
||||
- **Sample**
|
||||
* -
|
||||
- **name**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- Parameter's name
|
||||
- my_param
|
||||
* -
|
||||
- **type**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- Type of parameter, possible values are: variable, information, suffix or index
|
||||
- suffix
|
||||
* - Variable
|
||||
- **variable**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- variable's name
|
||||
- rougail.variable
|
||||
* - Variable (`mandatory`) information
|
||||
- **propertyerror**
|
||||
|
||||
`boolean`
|
||||
- If access to the variable is not possible due to a property
|
||||
(for example `disabled`) by default an error is returned.
|
||||
If the attribute is `False`, the parameter is not passed to the Jinja template.
|
||||
|
||||
**Default value**: `True`
|
||||
- True
|
||||
* - Information
|
||||
- **information**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- Name of the information whose value we want to retrieve.
|
||||
- doc
|
||||
|
||||
Samples
|
||||
--------------
|
||||
|
||||
Strict verification of values
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Here is a simple example of validating values:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
my_variable:
|
||||
validators:
|
||||
- type: jinja
|
||||
jinja: |
|
||||
{% if rougail.my_variable and not rougail.my_variable.islower() %}
|
||||
{{ rougail.my_variable }} is not lowercase string
|
||||
{% endif %}
|
||||
|
||||
|
||||
A verification function must take into account 2 important aspects:
|
||||
|
||||
- the value may not be entered (even if the variable is mandatory), the None value must be taken into account
|
||||
- if the value is invalid, a sentence must be returned with an explicit message.
|
||||
|
||||
From now on only `None` and lowercase values will be allowed.
|
||||
|
||||
Checking values with warning
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In the constraint, it is possible to specify the error level and put it as a warning:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
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:
|
||||
warnings_only: true
|
||||
|
||||
In this case a value with a capital letter will be accepted, but a warning message will appear.
|
||||
|
||||
Verification with parameters
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
my_hidden_variable:
|
||||
disabled: true
|
||||
my_variable:
|
||||
validators:
|
||||
- type: jinja
|
||||
jinja: |
|
||||
{% if param1 is defined and rougail.my_variable == param1 %}
|
||||
has same value as rougail.unknown_variable
|
||||
{% endif %}
|
||||
{% if param2 is defined and rougail.my_variable == param2 %}
|
||||
has same value as rougail.my_hidden_variable
|
||||
{% endif %}
|
||||
params:
|
||||
param1:
|
||||
type: variable
|
||||
variable: rougail.unknown_variable
|
||||
optional: true
|
||||
param2:
|
||||
type: variable
|
||||
variable: rougail.my_hidden_variable
|
||||
propertyerror: false
|
||||
|
||||
An example with a suffix type parameter:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
varname:
|
||||
multi: true
|
||||
default:
|
||||
- val1
|
||||
- val2
|
||||
my_dyn_family_:
|
||||
type: dynamic
|
||||
variable: rougail.varname
|
||||
description: 'Describe '
|
||||
my_dyn_var:
|
||||
type: string
|
||||
validators:
|
||||
- type: jinja
|
||||
jinja: |
|
||||
{% if rougail.my_dyn_family_.my_dyn_var == param1 %}
|
||||
forbidden!
|
||||
{% endif %}
|
||||
params:
|
||||
param1:
|
||||
type: suffix
|
||||
|
||||
In this example, we see a dynamic family. Two families will be created: `rougail.my_dyn_family_val1.my_dyn_var` and `rougail.my_dyn_family_val2.my_dyn_var`.
|
||||
|
||||
The value of the variable within this family cannot be equal to the value
|
||||
of the suffix (`val1` and `val2` respectively).
|
||||
|
||||
An example with an index type parameter:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
family:
|
||||
type: leadership
|
||||
leader:
|
||||
multi: true
|
||||
default:
|
||||
- val1
|
||||
- val2
|
||||
follower1:
|
||||
type: number
|
||||
validators:
|
||||
- type: jinja
|
||||
jinja: |
|
||||
{% if rougail.family.follower1 == param1 %}
|
||||
forbidden!
|
||||
{% endif %}
|
||||
params:
|
||||
param1:
|
||||
type: index
|
||||
|
||||
Redefinition
|
||||
---------------
|
||||
|
||||
In a first dictionary, let's declare our variable and its verification function:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
my_variable:
|
||||
validators:
|
||||
- type: jinja
|
||||
jinja: |
|
||||
{% if rougail.my_variable and not rougail.my_variable.islower() %}
|
||||
{{ rougail.my_variable }} is not lowercase string
|
||||
{% endif %}
|
||||
|
||||
In a second dictionary it is possible to redefine the calculation:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
my_variable:
|
||||
redefine: true
|
||||
validators:
|
||||
- type: jinja
|
||||
jinja: |
|
||||
{% if rougail.my_variable and ' ' in rougail.my_variable %}
|
||||
{{ rougail.my_variable }} has a space
|
||||
{% endif %}
|
||||
|
||||
In this case only this validator will be executed.
|
||||
|
||||
Here is a third dictionary in which we remove the validation:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
my_variable:
|
||||
redefine: true
|
||||
validators:
|
||||
207
docs/cli.rst
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
The Rougail Command Line Interface
|
||||
========================================
|
||||
|
||||
help
|
||||
------------
|
||||
|
||||
::
|
||||
|
||||
rougail -u yaml -h
|
||||
|
||||
Standard usage
|
||||
-----------------
|
||||
|
||||
::
|
||||
|
||||
rougail -m firefox/ -u yaml -yf config/02/config.yml
|
||||
|
||||
|
||||
|
||||
::
|
||||
|
||||
rougail --cli.versions
|
||||
|
||||
tiramisu: 5.2.0a9
|
||||
tiramisu-cmdline-parser: 0.7.0a1
|
||||
rougail: 1.2.0a29
|
||||
rougail-cli: 0.2.0a19
|
||||
rougail-user-data-environment: 0.1.0a9
|
||||
rougail-user-data-yaml: 0.2.0a11
|
||||
rougail-output-console: 0.2.0a11
|
||||
rougail-output-json: 0.2.0a8
|
||||
|
||||
::
|
||||
|
||||
env ROUGAIL_MANUAL.USE_FOR_HTTPS=true rougail -m structfile/proxy2.yml -u yaml environment --yaml.filename userdata/proxy.yml -o json
|
||||
|
||||
::
|
||||
|
||||
env ROUGAIL_MANUAL.USE_FOR_HTTPS=true rougail -m structfile/proxy2.yml -u yaml --yaml.filename userdata/proxy.yml -o json --json.get manual.https_proxy --json.read_write
|
||||
{
|
||||
"address": "toto.fr",
|
||||
"port": "8888"
|
||||
}
|
||||
|
||||
CLI root
|
||||
-------------
|
||||
|
||||
::
|
||||
|
||||
(.venv) ubuntu@monessai:~/workplace/rougail-tutorials$ env ROUGAIL_MANUAL.USE_FOR_HTTPS=true rougail -m firefox/ --cli.root manual.https_proxy -u yaml environment -yf ^Cnfig/01/config.yml --cli.read_write
|
||||
(.venv) ubuntu@monessai:~/workplace/rougail-tutorials$ cat config/01/config.yml
|
||||
---
|
||||
proxy_mode: Manual proxy configuration
|
||||
manual:
|
||||
http_proxy:
|
||||
address: http.proxy.net
|
||||
port: 3128
|
||||
use_for_https: false
|
||||
https_proxy:
|
||||
address: https.proxy.net
|
||||
(.venv) ubuntu@monessai:~/workplace/rougail-tutorials$ rougail -m firefox/ --cli.root manual.https_proxy -u yaml -yf config/01/config.yml
|
||||
[WARNING]: Deprecation warnings can be disabled by setting `deprecation_warnings=False` in ansible.cfg.
|
||||
[DEPRECATION WARNING]: Importing 'to_bytes' from 'ansible.module_utils._text' is deprecated. This feature will be removed from ansible-core version 2.24. Use ansible.module_utils.common.text.converters instead.
|
||||
╭────────────── Caption ───────────────╮
|
||||
│ Variable Default value │
|
||||
│ Modified value │
|
||||
│ (⏳ Original default value) │
|
||||
╰──────────────────────────────────────╯
|
||||
Variables:
|
||||
┣━━ 📓 HTTPS address: https.proxy.net ◀ loaded from the YAML file "config/01/config.yml" (⏳ https.proxy.net ◀ loaded from the YAML file "config/01/config.yml" ⏳ http.proxy.net)
|
||||
┗━━ 📓 HTTPS port: 3128
|
||||
|
||||
|
||||
.. FIXME: sortie normale:
|
||||
|
||||
.. FIXME: sortie pour n'afficher qu'une family:
|
||||
|
||||
::
|
||||
|
||||
rougail -m firefox/ -u yaml -yf config/01/config
|
||||
|
||||
on a:
|
||||
|
||||
::
|
||||
|
||||
Variables:
|
||||
┣━━ 📓 Configure Proxy Access to the Internet: Manual proxy configuration ◀ loaded from the YAML file "config/01/config.yml" (⏳ No proxy)
|
||||
┗━━ 📂 Manual proxy configuration
|
||||
┣━━ 📂 HTTP Proxy
|
||||
┃ ┣━━ 📓 HTTP address: http.proxy.net ◀ loaded from the YAML file "config/01/config.yml"
|
||||
┃ ┗━━ 📓 HTTP Port: 3128 ◀ loaded from the YAML file "config/01/config.yml" (⏳ 8080)
|
||||
┣━━ 📓 Also use this proxy for HTTPS: false ◀ loaded from the YAML file "config/01/config.yml" (⏳ true)
|
||||
┣━━ 📂 HTTPS Proxy
|
||||
┃ ┣━━ 📓 HTTPS address: https.proxy.net ◀ loaded from the YAML file "config/01/config.yml" (⏳ http.proxy.net)
|
||||
┃ ┗━━ 📓 HTTPS port: 3128
|
||||
┗━━ 📂 SOCKS Proxy
|
||||
┣━━ 📓 SOCKS address: http.proxy.net
|
||||
┣━━ 📓 SOCKS port: 3128
|
||||
┗━━ 📓 SOCKS host version used by proxy: v5
|
||||
|
||||
|
||||
for a more precise output:
|
||||
|
||||
::
|
||||
|
||||
rougail -m firefox/ -u yaml -yf config/01/config.yml --cli.root manual.https_proxy
|
||||
|
||||
we have
|
||||
|
||||
::
|
||||
|
||||
Variables:
|
||||
┣━━ 📓 HTTPS address: https.proxy.net ◀ loaded from the YAML file "config/01/config.yml" (⏳ https.proxy.net ◀ loaded from the YAML file "config/01/config.yml" ⏳ http.proxy.net)
|
||||
┗━━ 📓 HTTPS port: 3128
|
||||
|
||||
|
||||
Invalid user data error
|
||||
-----------------------------
|
||||
|
||||
::
|
||||
|
||||
rougail -m firefox/ -u yaml -yf config/02/config.yml --cli.invalid_user_data_error
|
||||
|
||||
Unknown user data error
|
||||
-----------------------------
|
||||
|
||||
The option "`--cli.unknown_user_data_error`" looks like "`--cli.invalid_user_data_error`" but here it concerns unknown variables (or here disabled or hidden but it amounts to the same thing) loaded into user data.
|
||||
|
||||
|
||||
.. note:: The `--cli.unknown_user_data_error` option changes the behaviour of the Rougail CLI's standard output:
|
||||
when an unknown (or disabled or hidden) variable is declared in the :term:`user data file <user data>`
|
||||
then it appears in the output as an error instead of a warning.
|
||||
|
||||
The output doc
|
||||
----------------
|
||||
|
||||
::
|
||||
|
||||
rougail -m structure.yml -o doc --doc.output_format github > README.md
|
||||
|
||||
::
|
||||
|
||||
doc:
|
||||
Generate documentation from structural files
|
||||
|
||||
-do [{console,asciidoc,html,github,gitlab,json}], --doc.output_format [{console,asciidoc,html,github,gitlab,json}]
|
||||
The output format of the generated documentation (default: console)
|
||||
-dm [{two_columns,three_columns,four_columns,five_columns,six_columns}], --doc.tabular_template [{two_columns,three_columns,four_columns,five_columns,six_columns}]
|
||||
Generate document with this tabular model (default: two_columns)
|
||||
-dc {variables,example,changelog} [{variables,example,changelog} ...], --doc.contents {variables,example,changelog} [{variables,example,changelog} ...]
|
||||
Generated content (default: variables)
|
||||
-dt [TITLE_LEVEL], --doc.title_level [TITLE_LEVEL]
|
||||
Starting title level (default: 1)
|
||||
--doc.default_values Modify values to document all variables (default: True)
|
||||
--doc.no-default_values
|
||||
--doc.document_a_type
|
||||
Documentation a structural type (default: False)
|
||||
--doc.no-document_a_type
|
||||
|
||||
|
||||
The formatter
|
||||
----------------
|
||||
|
||||
::
|
||||
|
||||
rougail -o formatter -m structure.yml > a.yml; mv a.yml structure.yml
|
||||
|
||||
The namespaces
|
||||
-----------------
|
||||
|
||||
::
|
||||
|
||||
rougail -m structure.yml -u yaml -yf userdata.yml -s intranet -xn hosts -xd 0 hosts.yml
|
||||
|
||||
|
||||
::
|
||||
|
||||
rougail -m structure.yml -u yaml -yf userdata.yml -s intranet -xn hosts orem srem prom -xd 0 hosts.yml -xd 1 packages/OREM -xd 2 packages/SREM -xd 3 packages/SREP
|
||||
|
||||
Commandline user data
|
||||
----------------------------
|
||||
|
||||
Commandline user data can be used:
|
||||
|
||||
::
|
||||
|
||||
rougail -m mon_fichier.yml -u commandline --family.variable pouet
|
||||
|
||||
Ansible export
|
||||
-------------------
|
||||
|
||||
rougail -m structure.yml -u yaml -yf userdata.yml -s intranet -xn hosts -xd 0 hosts.yml -o ansible > ansible.json
|
||||
|
||||
::
|
||||
|
||||
ansible-inventory -i $(which rougail) --list
|
||||
|
||||
Ansible lists your inventory
|
||||
|
||||
::
|
||||
|
||||
ansible-inventory -i $(which rougail) --host tutu.fr
|
||||
|
||||
::
|
||||
|
||||
ansible-playbook -i $(which rougail) install.yml
|
||||
|
||||
|
|
@ -1,240 +0,0 @@
|
|||
Calculated properties
|
||||
==========================
|
||||
|
||||
Synopsis
|
||||
------------
|
||||
|
||||
Calculated properties allow you to add or remove properties to a :term:`variable`
|
||||
or a :term:`family` depending on the context.
|
||||
|
||||
Here is the list of editable properties:
|
||||
|
||||
.. list-table::
|
||||
:widths: 15 15 25
|
||||
:header-rows: 1
|
||||
|
||||
* - **Attribute applicable on**
|
||||
- **Property's name**
|
||||
- Comment
|
||||
|
||||
* - Variable
|
||||
|
||||
Family
|
||||
- hidden
|
||||
- Hides a variable or a family, in this case it is not accessible in `read-write` mode,
|
||||
but remains accessible in a calculation or in `read-only` mode
|
||||
* - Variable
|
||||
|
||||
Family
|
||||
- disabled
|
||||
- Deactivates a variable or family, in this case it is never accessible
|
||||
* - Variable
|
||||
- mandatory
|
||||
- The variable expects a value other than `None` or `[]` for multiple variables
|
||||
|
||||
A property can be calculated. In this case we have two possibilities:
|
||||
|
||||
- calculation via Jinja
|
||||
- calculation via a variable
|
||||
|
||||
Parameters
|
||||
---------------
|
||||
|
||||
.. list-table::
|
||||
:widths: 15 25 20 15
|
||||
:header-rows: 1
|
||||
|
||||
* - **Calculation type**
|
||||
- **Parameter**
|
||||
- **Comment**
|
||||
- **Sample**
|
||||
* -
|
||||
- **type**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- Calculation type, possible values are: jinja, variable, information, suffix or index
|
||||
- jinja
|
||||
* - Jinja
|
||||
- **jinja**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- Jinja template . For a multiple variable, each line represents a value.
|
||||
- {% if rougail.variable %}
|
||||
|
||||
{{ rougail.variable }}
|
||||
|
||||
{% endif %}
|
||||
* - Jinja
|
||||
- **params**
|
||||
|
||||
`list`
|
||||
- Additional parameters passed to the Jinja template
|
||||
-
|
||||
* - Variable
|
||||
- **variable**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- Name of the associated variable.
|
||||
|
||||
.. attention:: The variable must be of `boolean` type.
|
||||
- rougail.variable
|
||||
* - Variable
|
||||
- **propertyerror**
|
||||
|
||||
`boolean`
|
||||
- If access to the variable is not possible due to a property
|
||||
(for example `disabled`) by default an error is returned.
|
||||
If the attribute is `False`, the calculated value is False.
|
||||
|
||||
**Default value**: `True`
|
||||
- False
|
||||
|
||||
In the case of a Jinja type calculation, it is possible to have parameters.
|
||||
|
||||
There are two types of parameter:
|
||||
|
||||
- the standard parameters (string, boolean, integer, null), in this case just do: "key: value"
|
||||
|
||||
- advanced settings:
|
||||
|
||||
- parameter via a variable
|
||||
- parameter via information
|
||||
- parameter via a suffix: in the case of a variable in a dynamic family
|
||||
- parameter via an index: in the case of a follower variable
|
||||
|
||||
.. list-table::
|
||||
:widths: 15 25 20 15
|
||||
:header-rows: 1
|
||||
|
||||
* - **Parameter's type**
|
||||
- **Parameter**
|
||||
- **Comments**
|
||||
- **Sample**
|
||||
* -
|
||||
- **name**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- parameter's name
|
||||
- my_param
|
||||
* -
|
||||
- **type**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- Parameter's type, possible values are: variable, information, suffix or index
|
||||
- suffix
|
||||
* - Variable
|
||||
- **variable**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- variable's name
|
||||
- rougail.variable
|
||||
* - Variable (`mandatory`) Information
|
||||
- **propertyerror**
|
||||
|
||||
`boolean`
|
||||
- If access to the variable is not possible due to a property (for example `disabled`) by default an error is returned. If the attribute is False, the parameter is not passed to the Jinja template.
|
||||
|
||||
**Default value**: `True`
|
||||
- False
|
||||
* - Variable
|
||||
- **optional**
|
||||
|
||||
`boolean`
|
||||
- The variable may not exist depending on YAML file imports. If the optional parameter is True, the parameter will simply be deleted if the variable does not exist.
|
||||
**Default value**: `False`
|
||||
- True
|
||||
|
||||
* - information
|
||||
- **information**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- Name of the information whose value we want to retrieve.
|
||||
- doc
|
||||
|
||||
Samples
|
||||
------------
|
||||
|
||||
A Jinja-type calculated property
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
It is possible to write the condition in Jinja:
|
||||
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
condition:
|
||||
default: 'do not hide!'
|
||||
my_variable:
|
||||
hidden:
|
||||
type: jinja
|
||||
jinja: |
|
||||
{% if rougail.condition and rougail.condition == "hide!" %}
|
||||
this rougail.condition value is 'hide!'
|
||||
{% endif %}
|
||||
|
||||
|
||||
In this case the variable is hidden if the value of the variable "rougail.condition" is `hide!` and it did not hide for any other value. Be careful, always take into consideration that "rougail.condition" can be equal to `None`.
|
||||
|
||||
The message returned by the function is visible in the error message in the event of an access problem:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> from rougail import Rougail, RougailConfig
|
||||
>>> RougailConfig['dictionaries_dir'] = ['dict']
|
||||
>>> rougail = Rougail()
|
||||
>>> config = rougail.get_config()
|
||||
>>> config.property.read_write()
|
||||
[..]
|
||||
tiramisu.error.PropertiesOptionError: cannot access to option "my_variable" because has property "hidden" (this rougail.condition value is 'hide!')
|
||||
|
||||
It is possible to use parameters when calculating properties as for calculating the `default` attribute.
|
||||
|
||||
A calculated property of variable type
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A variable can therefore be calculated via the result of another variable. Please note, this other variable must be of `boolean` type:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
condition:
|
||||
type: boolean
|
||||
my_variable:
|
||||
hidden:
|
||||
type: variable
|
||||
variable: rougail.condition
|
||||
|
||||
If the value of the variable "rougail.condition" is `True` then the variable "rougail.my_variable" is hidden.
|
||||
|
||||
Redefintion
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
It may be that in a dictionary we decide to define a condition.
|
||||
|
||||
To delete the calculation from a variable, simply do in a new dictionary:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
my_variable:
|
||||
redefine: true
|
||||
hidden:
|
||||
|
||||
145
docs/conf.py
|
|
@ -1,24 +1,20 @@
|
|||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file does only contain a selection of the most common options. For a
|
||||
# full list see the documentation:
|
||||
# http://www.sphinx-doc.org/en/master/config
|
||||
|
||||
# -- Path setup --------------------------------------------------------------
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
import sys, os
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
#sys.path.append(os.path.abspath('ext'))
|
||||
sys.path.append('.')
|
||||
|
||||
#---- debug mode ----
|
||||
# shows/hides the todos
|
||||
todo_include_todos = True
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = 'Rougail'
|
||||
copyright = '2019-2023, Silique'
|
||||
copyright = '2019-2026, Silique'
|
||||
author = 'gwen'
|
||||
|
||||
# The short X.Y version
|
||||
|
|
@ -33,55 +29,64 @@ release = '1.0'
|
|||
#
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
|
||||
extensions = [
|
||||
'sphinx.ext.extlinks', 'sphinx_lesson',
|
||||
#'myst_parser', 'sphinx.ext.extlinks'
|
||||
'sphinx.ext.extlinks', 'sphinx_lesson', 'sphinx.ext.todo',
|
||||
'ext.xref', 'ext.extinclude', 'sphinxnotes.strike',
|
||||
]
|
||||
#
|
||||
#myst_enable_extensions = [
|
||||
# "amsmath",
|
||||
# "attrs_inline",
|
||||
# "colon_fence",
|
||||
# "deflist",
|
||||
# "dollarmath",
|
||||
# "fieldlist",
|
||||
# "html_admonition",
|
||||
# "html_image",
|
||||
## "linkify",
|
||||
# "replacements",
|
||||
# "smartquotes",
|
||||
# "strikethrough",
|
||||
# "substitution",
|
||||
# "tasklist",
|
||||
#]
|
||||
|
||||
#---- disable highlight warnings with yaml new version ----
|
||||
# Configuration pour les blocs de code
|
||||
highlight_language = 'yaml'
|
||||
|
||||
# Options spécifiques pour YAML
|
||||
highlight_options = {
|
||||
'yaml': {
|
||||
'startinline': True
|
||||
}
|
||||
}
|
||||
|
||||
suppress_warnings = [
|
||||
'misc.highlighting_failure'
|
||||
]
|
||||
|
||||
#---- xref links ----
|
||||
#import the xref.py extension
|
||||
xref_links = {"link_name" : ("user text", "url")}
|
||||
|
||||
#link_name = "Sphinx External Links"
|
||||
#user_text = "modified External Links Extension"
|
||||
#url = "http://www.sphinx-doc.org/en/stable/ext/extlinks.html"
|
||||
#enables syntax like:
|
||||
" :xref:`tiramisu` "
|
||||
links = {
|
||||
'tiramisu': ('Tiramisu', 'https://tiramisu.readthedocs.io/en/latest/'),
|
||||
'tiramisu library': ('Tiramisu library homepage', 'https://forge.cloud.silique.fr/stove/tiramisu'),
|
||||
}
|
||||
xref_links.update(links)
|
||||
|
||||
#---- ext links ----
|
||||
# **extlinks** 'sphinx.ext.extlinks',
|
||||
# enables syntax like :proxy:`my source <hello>` in the src files
|
||||
extlinks = {'proxy': ('/proxy/%s.html',
|
||||
'external link: ')}
|
||||
# enables syntax like
|
||||
" :source:`v1.1_010/firefox/00-proxy.yml` "
|
||||
extlinks = {'source': ('https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/%s',
|
||||
'source: %s'),
|
||||
'tiramisu': ('https://tiramisu.readthedocs.io/en/latest/%s', 'tiramisu: %s'),
|
||||
'tutorial': ('https://forge.cloud.silique.fr/stove/rougail-tutorials/%s', 'tutorial %s'),
|
||||
}
|
||||
|
||||
#---- options for HTML output ----
|
||||
default_role = "code"
|
||||
|
||||
html_theme = "sphinx_rtd_theme"
|
||||
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
html_short_title = "Rougail"
|
||||
html_title = "Rougail documenation"
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
html_title = "Rougail documentation"
|
||||
html_show_sourcelink = False
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
html_show_sphinx = False
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
html_show_copyright = True
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = None
|
||||
html_static_path = ['_static']
|
||||
html_css_files = ['terminal.css', 'custom.css']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
|
@ -109,41 +114,21 @@ language = 'en'
|
|||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
exclude_patterns = ['.venv', 'build', '_build', 'Thumbs.db', '.DS_Store']
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = None
|
||||
# ------------------------------------------------------------------------------
|
||||
## underline role
|
||||
## sample: Voici du texte :underline:`souligné`.
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import roles
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
#html_theme = 'alabaster'
|
||||
# **themes**
|
||||
#html_theme = 'bizstyle'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
# html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# Custom sidebar templates, must be a dictionary that maps document names
|
||||
# to template names.
|
||||
#
|
||||
# The default sidebars (for documents that don't match any pattern) are
|
||||
# defined by theme itself. Builtin themes are using these templates by
|
||||
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
|
||||
# 'searchbox.html']``.
|
||||
#
|
||||
# html_sidebars = {}
|
||||
def underline_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
node = nodes.inline(rawtext, text, **options)
|
||||
node['classes'].append('underline')
|
||||
return [node], []
|
||||
|
||||
def setup(app):
|
||||
app.add_css_file('css/custom.css')
|
||||
app.add_role('underline', underline_role)
|
||||
app.add_css_file('css/custom.css')
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ The functions file
|
|||
|
||||
The file which contains the custom functions is managed in the `functions_file` key and has the default value `/srv/rougail/functions.py`. This key can contain a list if there are several files.
|
||||
|
||||
.. important:: Functions must return a value, even if the variable being calculated is a :term:`multiple` variable. If the function can return a multiple value (a list), you must put the name of the function in the `multi_functions` key.
|
||||
.. important:: Functions must return a value, even if the variable being calculated is a :term:`multiple <multi>` variable. If the function can return a multiple value (a list), you must put the name of the function in the `multi_functions` key.
|
||||
|
||||
The `auto_freeze` variable
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
|||
|
|
@ -58,3 +58,285 @@ We use black
|
|||
- id: black
|
||||
|
||||
And some YAML and JSON validators.
|
||||
|
||||
|
||||
----
|
||||
|
||||
The pre commit tool
|
||||
----------------------
|
||||
|
||||
**pre-commit** is a fantastic tool for automating code quality checks
|
||||
before you commit your changes. It’s especially useful in Python
|
||||
projects for running linters, formatters, and other checks
|
||||
automatically.
|
||||
|
||||
Here’s a **practical, minimal example** to get you started with a small
|
||||
Python project.
|
||||
|
||||
|
||||
1. Install pre-commit
|
||||
---------------------
|
||||
|
||||
First, install the ``pre-commit`` package:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
pip install pre-commit
|
||||
|
||||
|
||||
2. Create a ``.pre-commit-config.yaml`` File
|
||||
--------------------------------------------
|
||||
|
||||
In the root of your Python project, create a file named
|
||||
``.pre-commit-config.yaml`` with the following content:
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.4.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
- id: check-yaml
|
||||
- id: check-added-large-files
|
||||
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 23.12.1
|
||||
hooks:
|
||||
- id: black
|
||||
|
||||
- repo: https://github.com/pycqa/flake8
|
||||
rev: 6.1.0
|
||||
hooks:
|
||||
- id: flake8
|
||||
|
||||
This config: - Uses popular pre-commit hooks for basic checks - Adds
|
||||
`Black <https://github.com/psf/black>`__ for code formatting - Adds
|
||||
`Flake8 <https://github.com/pycqa/flake8>`__ for linting
|
||||
|
||||
|
||||
3. Install the Git Hook
|
||||
-----------------------
|
||||
|
||||
Run this command in your project root:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
pre-commit install
|
||||
|
||||
This sets up a Git hook that runs the checks before each commit.
|
||||
|
||||
|
||||
4. Try It Out
|
||||
-------------
|
||||
|
||||
Now, when you try to commit:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
git add .
|
||||
git commit -m "My commit message"
|
||||
|
||||
pre-commit will run the hooks. If any check fails, you’ll see output
|
||||
like this:
|
||||
|
||||
::
|
||||
|
||||
Trim Trailing Whitespace............................................Passed
|
||||
Fix End of Files....................................................Passed
|
||||
Check Yaml..........................................................Passed
|
||||
Check for added large files..........................................Passed
|
||||
Black..............................................................Failed
|
||||
- hook id: black
|
||||
- exit code: 1
|
||||
|
||||
Reformatted /path/to/your/file.py
|
||||
All done! ✨ 🍰 ✨
|
||||
1 file reformatted.
|
||||
|
||||
If any hook fails, fix the issues and try committing again.
|
||||
|
||||
|
||||
5. (Optional) Run pre-commit Manually
|
||||
-------------------------------------
|
||||
|
||||
You can run all hooks against all files at any time:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
pre-commit run --all-files
|
||||
|
||||
|
||||
6. Update Hooks
|
||||
---------------
|
||||
|
||||
To update your hooks to the latest versions:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
pre-commit autoupdate
|
||||
|
||||
**Summary Table**
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
==== ===================== ==============================
|
||||
Step Action Command
|
||||
==== ===================== ==============================
|
||||
1 Install pre-commit ``pip install pre-commit``
|
||||
2 Create config file ``.pre-commit-config.yaml``
|
||||
3 Install Git hook ``pre-commit install``
|
||||
4 Commit and see checks ``git commit -m "..."``
|
||||
5 Run manually ``pre-commit run --all-files``
|
||||
6 Update hooks ``pre-commit autoupdate``
|
||||
==== ===================== ==============================
|
||||
|
||||
more python linters
|
||||
-------------------
|
||||
|
||||
Customizing your ``.pre-commit-config.yaml`` to include **pylint**,
|
||||
**ruff**, and additional hooks is a great way to maintain code quality.
|
||||
Here’s how you can structure your config for a robust setup:
|
||||
|
||||
**1. Basic Setup with pylint and ruff**
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Here’s a starting point for your ``.pre-commit-config.yaml``:
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.4.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
- id: check-yaml
|
||||
- id: check-added-large-files
|
||||
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.1.6
|
||||
hooks:
|
||||
- id: ruff
|
||||
args: [--fix, --exit-non-zero-on-fix]
|
||||
|
||||
- repo: https://github.com/pycqa/pylint
|
||||
rev: v3.0.3
|
||||
hooks:
|
||||
- id: pylint
|
||||
args: [--rcfile=.pylintrc] # Optional: specify a pylint config file
|
||||
|
||||
**2. Adding More Hooks**
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Here are some popular hooks you might want to add:
|
||||
|
||||
**a. Black (Code Formatter)**
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 23.12.1
|
||||
hooks:
|
||||
- id: black
|
||||
|
||||
**b. Mypy (Static Type Checker)**
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v1.8.0
|
||||
hooks:
|
||||
- id: mypy
|
||||
|
||||
**c. isort (Import Sorter)**
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
- repo: https://github.com/pycqa/isort
|
||||
rev: 5.13.2
|
||||
hooks:
|
||||
- id: isort
|
||||
|
||||
**d. Bandit (Security Linter)**
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
- repo: https://github.com/pycqa/bandit
|
||||
rev: 1.7.7
|
||||
hooks:
|
||||
- id: bandit
|
||||
|
||||
**3. Full Example Config**
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Here’s a full example with all the above hooks:
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.4.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
- id: check-yaml
|
||||
- id: check-added-large-files
|
||||
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.1.6
|
||||
hooks:
|
||||
- id: ruff
|
||||
args: [--fix, --exit-non-zero-on-fix]
|
||||
|
||||
- repo: https://github.com/pycqa/pylint
|
||||
rev: v3.0.3
|
||||
hooks:
|
||||
- id: pylint
|
||||
args: [--rcfile=.pylintrc]
|
||||
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 23.12.1
|
||||
hooks:
|
||||
- id: black
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v1.8.0
|
||||
hooks:
|
||||
- id: mypy
|
||||
|
||||
- repo: https://github.com/pycqa/isort
|
||||
rev: 5.13.2
|
||||
hooks:
|
||||
- id: isort
|
||||
|
||||
- repo: https://github.com/pycqa/bandit
|
||||
rev: 1.7.7
|
||||
hooks:
|
||||
- id: bandit
|
||||
|
||||
**4. Customizing Hooks**
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- **pylint**: You can specify a config file (``.pylintrc``) or pass
|
||||
arguments directly.
|
||||
- **ruff**: You can customize rules in ``pyproject.toml`` or
|
||||
``.ruff.toml``.
|
||||
- **Black, isort, mypy**: Each can be configured via their respective
|
||||
config files.
|
||||
|
||||
**5. Installing and Running**
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
1. Save the config to ``.pre-commit-config.yaml``.
|
||||
|
||||
2. Run:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
pre-commit install
|
||||
pre-commit run --all-files
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
Dictionary conventions
|
||||
=========================
|
||||
|
||||
Dictionary file naming convention
|
||||
------------------------------------
|
||||
|
||||
The order of dictionaries is important for the order in which variables and families are created.
|
||||
|
||||
The files must therefore be started with two numbers followed by a hyphen.
|
||||
|
||||
For example: `00-base.xml`
|
||||
|
||||
Naming convention for families and variables
|
||||
-----------------------------------------------
|
||||
|
||||
The only restriction on the name of families and variables is that the name must not start with the `"_"` (undescore) character.
|
||||
|
||||
However, it is preferable to only use lowercase ASCII letters, numbers and the `"_"` (undescore) character.
|
||||
The snake case typographic convention is therefore used.
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
The dictionaries
|
||||
=====================
|
||||
|
||||
What do you mean by :term:`dictionary`?
|
||||
-------------------------------------------
|
||||
|
||||
A :term:`dictionary` is a YAML file whose structure is described in this documentation page.
|
||||
|
||||
A dictionary contains a set of variables loaded into :term:`Tiramisu`, usable at any time, especially in a :term:`templates`.
|
||||
|
||||
:term:`Families` and :term:`variables` can be defined in several dictionaries. These dictionaries are then aggregated.
|
||||
|
||||
Dictionaries are loaded in the directory order defined by the `dictionaries_dir` configuration parameter.
|
||||
Each directory is loaded one after the other.
|
||||
Inside these directories the YAML files will be classified in alphabetical order.
|
||||
|
||||
There is no alphabetical ordering of all YAML files in all directories.
|
||||
|
||||
It is also possible to :term:`redefine` elements to change the behavior of a family or a variable.
|
||||
|
||||
The default namespace
|
||||
-------------------------
|
||||
|
||||
The families and variables contained in these dictionaries are ordered, by default, in the `rougail` namespace. It is possible to change the name of this namespace :doc:`with the `variable_namespace` parameter of the configuration <configuration>`.
|
||||
|
||||
This namespace is a bit special, it can access variables in another namespace.
|
||||
|
||||
The extra dictionaries
|
||||
---------------------------
|
||||
|
||||
An extra is a different namespace. The idea is to be able to classify the variables by theme.
|
||||
|
||||
Extra namespaces must be declared :doc:`when configuring Rougail <configuration>`.
|
||||
|
||||
In this namespace we cannot access variables from another `extra` namespace.
|
||||
On the other hand, it is possible to access the variable of the default namespace.
|
||||
222
docs/documentation.rst
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
Documentation Writing Guide
|
||||
===========================
|
||||
|
||||
This project uses **Sphinx** to generate documentation from reStructuredText (``.rst``) files.
|
||||
Following a few consistent conventions will keep our docs clear, maintainable, and correctly rendered.
|
||||
|
||||
Section title levels
|
||||
--------------------
|
||||
|
||||
Use the following underline-only characters for headings:
|
||||
|
||||
- **Level 1 titles** (page titles): underline with ``======`` (equal signs)
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: rst
|
||||
|
||||
My Page Title
|
||||
=============
|
||||
|
||||
- **Level 2 headings** (major sections): underline with ``-------`` (dashes)
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: rst
|
||||
|
||||
My Second-level Heading
|
||||
-----------------------
|
||||
|
||||
- **Level 3 headings** (sub-sections): underline with ``~~~~~~~~~~~`` (tildes)
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: rst
|
||||
|
||||
My Third-level Heading
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Do **not** skip levels (e.g. going from a level 1 title directly to a level 3 heading).
|
||||
|
||||
Handling TODOs and FIXMEs
|
||||
------------------------------
|
||||
|
||||
We use two complementary mechanisms to track pending work:
|
||||
|
||||
- **FIXME** – keyword for things that need **correction** (bugs, typos, broken links, wrong logic)
|
||||
- **``.. todo::`` directive** – for things that need to be **done** (missing sections, improvements, new features)
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: rst
|
||||
|
||||
FIXME: The example below uses a deprecated function.
|
||||
|
||||
.. todo::
|
||||
Add a section about configuration file formats.
|
||||
|
||||
To show or hide todos in the rendered output, set in your ``conf.py``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
todo_include_todos = True # shows todos in the HTML output
|
||||
# todo_include_todos = False # hides them
|
||||
|
||||
When ``True``, all ``.. todo::`` directives appear inline. Use this for local reviews; keep it ``False`` for public releases unless you want todos visible.
|
||||
|
||||
Extensions
|
||||
----------
|
||||
|
||||
Our Sphinx configuration uses the following extensions:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
extensions = [
|
||||
'sphinx.ext.extlinks',
|
||||
'sphinx_lesson',
|
||||
'sphinx.ext.todo',
|
||||
]
|
||||
|
||||
- **``sphinx.ext.todo``** – enables the ``.. todo::`` directive and the ``todo_include_todos`` setting.
|
||||
- **``sphinx_lesson``** – provides lesson‑specific markup (see its documentation for details).
|
||||
- **``sphinx.ext.extlinks``** – creates short aliases for long, repetitive URLs.
|
||||
|
||||
External links (extlinks)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The ``extlinks`` extension defines convenient shortcuts. For each alias you write ``:<alias>:<suffix>``, and Sphinx expands it into a full URL.
|
||||
|
||||
Our configuration:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
extlinks = {
|
||||
'source': ('https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/%s',
|
||||
'source: %s'),
|
||||
'tiramisu': ('https://tiramisu.readthedocs.io/en/latest/%s', 'tiramisu: %s'),
|
||||
'tutorial': ('https://forge.cloud.silique.fr/stove/rougail-tutorials/%s', 'tutorial %s'),
|
||||
}
|
||||
|
||||
Usage examples:
|
||||
|
||||
- ``:source:`v1.1_010/firefox/00-proxy.yml``` → links to the raw file at that tag, displayed as ``source: v1.1_010/firefox/00-proxy.yml``
|
||||
- ``:tiramisu:`configuration.html``` → links to the Tiramisu documentation, displayed as ``tiramisu: configuration.html``
|
||||
- ``:tutorial:`README.md``` → links to the rougail-tutorials file, displayed as ``tutorial README.md``
|
||||
|
||||
The first string in each tuple is the URL pattern (the ``%s`` is replaced by your custom text). The second string is the visible link title (where ``%s`` is again replaced by your custom text).
|
||||
|
||||
General writing tips
|
||||
--------------------
|
||||
|
||||
- **Keep lines wrapped at 80–90 characters** for readability in plain text.
|
||||
- **Use blank lines** before and after headings, lists, code blocks, and tables.
|
||||
- **Prefer explicit cross-references** with Sphinx roles like ``:ref:`` or ``:doc:`` over raw URLs.
|
||||
- **Write in present tense** and imperative mood for instructions (e.g. “Define the function”, not “The function should be defined”).
|
||||
- **Use ``.. code-block::``** for syntax highlighting. Always specify the language (``python``, ``bash``, ``json``, etc.).
|
||||
- **Review the rendered output** with ``make html`` before committing.
|
||||
|
||||
File organisation
|
||||
-----------------
|
||||
|
||||
- Place ``.rst`` files in the ``source/`` directory (or as defined in your Sphinx ``conf.py``).
|
||||
- One page per logical topic – split long documents into sub-pages and link them with ``toctree``.
|
||||
- Name files with lowercase letters and hyphens instead of underscores or spaces (e.g. ``api-reference.rst``).
|
||||
|
||||
Example – a typical page
|
||||
------------------------
|
||||
|
||||
.. code-block:: rst
|
||||
|
||||
Using the Logger
|
||||
================
|
||||
|
||||
Basic setup
|
||||
-----------
|
||||
|
||||
Add the following to your configuration:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import logging
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
Advanced filtering
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
For more complex filtering, see :ref:`custom-filters`.
|
||||
|
||||
FIXME: The example above should mention log levels.
|
||||
|
||||
.. todo::
|
||||
Add a section about rotating log files.
|
||||
|
||||
For any questions about Sphinx directives or reStructuredText syntax, check the `official Sphinx documentation <https://www.sphinx-doc.org/>`_.
|
||||
|
||||
Displaying YAML files
|
||||
-------------------------
|
||||
|
||||
We host our data files on a remote forge. To include and display YAML files directly from that remote repository, we use a custom directive called **``extinclude``**.
|
||||
|
||||
This directive works like the standard ``.. include::`` but fetches content from a **remote URL** instead of a local file.
|
||||
|
||||
YAML files coming from a data repository
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Use the following syntax to include a remote YAML file with syntax highlighting:
|
||||
|
||||
.. code-block:: rst
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_170/firefox/60-dns_over_https.yml
|
||||
:language: yaml
|
||||
:caption: The :file:`firefox/60-dns_over_https.yml` with the jinja validator
|
||||
|
||||
Explanation of options:
|
||||
|
||||
- **``extinclude:: <URL>``** – the full URL to the raw YAML file on the remote forge
|
||||
- **``:language: yaml``** – enables YAML syntax highlighting in the rendered output
|
||||
- **``:caption: <text>``** – adds a descriptive caption below the code block
|
||||
|
||||
Displaying terminal commands
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To include and display a text file containing bash commands or terminal output, use the ``raw`` directive with the ``terminal`` class:
|
||||
|
||||
.. code-block:: rst
|
||||
|
||||
.. raw:: html
|
||||
:class: terminal
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_033/config/02/cmd_ro.txt
|
||||
|
||||
This fetches the remote text file and renders it with terminal-style formatting (typically a dark background, monospaced font, and command-line appearance).
|
||||
|
||||
Displaying HTML output
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To include and display an HTML file from the remote forge, use the ``raw`` directive with the ``output`` class:
|
||||
|
||||
.. code-block:: rst
|
||||
|
||||
.. raw:: html
|
||||
:class: output
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_033/config/02/output_ro.html
|
||||
|
||||
This fetches the remote HTML file and embeds it directly into the generated documentation page.
|
||||
|
||||
Summary
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
+----------------------------+----------------------+---------------------------+
|
||||
| Content type | Directive | Class |
|
||||
+============================+======================+===========================+
|
||||
| YAML files | ``.. extinclude::`` | ``:language: yaml`` |
|
||||
+----------------------------+----------------------+---------------------------+
|
||||
| Terminal commands / text | ``.. raw:: html`` | ``:class: terminal`` |
|
||||
+----------------------------+----------------------+---------------------------+
|
||||
| HTML output | ``.. raw:: html`` | ``:class: output`` |
|
||||
+----------------------------+----------------------+---------------------------+
|
||||
|
||||
|
||||
|
||||
All three directives fetch content from our remote forge at build time, ensuring the documentation always displays the latest version of the referenced files.
|
||||
|
||||
95
docs/ext/extinclude.py
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from docutils import nodes
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.util.docutils import SphinxDirective, SphinxRole
|
||||
from sphinx.util.typing import ExtensionMetadata
|
||||
from sphinx.directives.code import LiteralInclude, container_wrapper
|
||||
|
||||
import requests
|
||||
from requests.exceptions import RequestException
|
||||
from docutils.parsers.rst import directives
|
||||
|
||||
class ExtInclude(LiteralInclude):
|
||||
"""A directive to include code that comes from an url
|
||||
|
||||
Sample use::
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_010/firefox/00-proxy.yml
|
||||
:linenos:
|
||||
:language: yaml
|
||||
:caption: this is a interesting code
|
||||
|
||||
- parameter required
|
||||
- linenos, language and caption are optionnal.
|
||||
|
||||
:default language: yaml
|
||||
:default caption: extinclude parameter (url)
|
||||
|
||||
"""
|
||||
|
||||
def run(self) -> list[nodes.Node]:
|
||||
url = self.arguments[0]
|
||||
|
||||
try:
|
||||
headers = {
|
||||
'accept': 'application/text',
|
||||
'Content-Type': 'application/text',
|
||||
}
|
||||
response = requests.get(url, headers=headers)
|
||||
response.raise_for_status() # This will raise an exception for 4xx/5xx status codes
|
||||
|
||||
except requests.exceptions.HTTPError as e:
|
||||
if response.status_code == 404:
|
||||
error_msg = f"extinclude: URL not found (404): {url}"
|
||||
else:
|
||||
error_msg = f"extinclude: HTTP error {response.status_code}: {url}"
|
||||
|
||||
# Create an error node that will be displayed in the documentation
|
||||
error_node = nodes.error()
|
||||
para = nodes.paragraph()
|
||||
para += nodes.Text(error_msg)
|
||||
error_node += para
|
||||
self.state.document.reporter.warning(error_msg, line=self.lineno)
|
||||
return [error_node]
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
error_msg = f"extinclude: Failed to fetch URL {url}: {str(e)}"
|
||||
|
||||
# Create an error node that will be displayed in the documentation
|
||||
error_node = nodes.error()
|
||||
para = nodes.paragraph()
|
||||
para += nodes.Text(error_msg)
|
||||
error_node += para
|
||||
self.state.document.reporter.warning(error_msg, line=self.lineno)
|
||||
return [error_node]
|
||||
|
||||
code = response.text
|
||||
|
||||
literal = nodes.literal_block(code, code)
|
||||
if 'language' in self.options:
|
||||
literal['language'] = self.options['language']
|
||||
else:
|
||||
literal['language'] = 'yaml'
|
||||
literal['linenos'] = 'linenos' in self.options
|
||||
if 'caption' in self.options:
|
||||
caption = self.options.get('caption')
|
||||
else:
|
||||
caption = url
|
||||
literal['caption'] = caption
|
||||
if 'name' in self.options:
|
||||
literal['name'] = self.options.get('name')
|
||||
literal = container_wrapper(self, literal, caption)
|
||||
self.add_name(literal)
|
||||
|
||||
return [literal]
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> ExtensionMetadata:
|
||||
app.add_directive('extinclude', ExtInclude)
|
||||
|
||||
return {
|
||||
'version': '0.1',
|
||||
'parallel_read_safe': True,
|
||||
'parallel_write_safe': True,
|
||||
}
|
||||
67
docs/ext/xref.py
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
"""adds link url in the global scope
|
||||
|
||||
sample use:
|
||||
|
||||
:xref:`Tiramisu <tiramisu>`
|
||||
|
||||
You must declare in the `conf.py`
|
||||
|
||||
::
|
||||
|
||||
#---- xref links ----
|
||||
#import the xref.py extension
|
||||
xref_links = {"link_name" : ("user text", "url")}
|
||||
#link_name = "Sphinx External Links"
|
||||
#user_text = "modified External Links Extension"
|
||||
#url = "http://www.sphinx-doc.org/en/stable/ext/extlinks.html"
|
||||
#enables syntax like:
|
||||
" :xref:`tiramisu` "
|
||||
links = {
|
||||
'tiramisu': ('Tiramisu', 'https://tiramisu.readthedocs.io/en/latest/'),
|
||||
'tiramisu library': ('Tiramisu library homepage', 'https://forge.cloud.silique.fr/stove/tiramisu'),
|
||||
}
|
||||
xref_links.update(links)
|
||||
|
||||
|
||||
|
||||
"""
|
||||
from docutils import nodes
|
||||
|
||||
from sphinx.util import caption_ref_re
|
||||
|
||||
def xref( typ, rawtext, text, lineno, inliner, options={}, content=[] ):
|
||||
|
||||
title = target = text
|
||||
titleistarget = True
|
||||
# look if explicit title and target are given with `foo <bar>` syntax
|
||||
brace = text.find('<')
|
||||
if brace != -1:
|
||||
titleistarget = False
|
||||
m = caption_ref_re.match(text)
|
||||
if m:
|
||||
target = m.group(2)
|
||||
title = m.group(1)
|
||||
else:
|
||||
# fallback: everything after '<' is the target
|
||||
target = text[brace+1:]
|
||||
title = text[:brace]
|
||||
|
||||
link = xref.links[target]
|
||||
|
||||
if brace != -1:
|
||||
pnode = nodes.reference(target, title, refuri=link[1])
|
||||
else:
|
||||
pnode = nodes.reference(target, link[0], refuri=link[1])
|
||||
|
||||
return [pnode], []
|
||||
|
||||
def get_refs(app):
|
||||
|
||||
xref.links = app.config.xref_links
|
||||
|
||||
def setup(app):
|
||||
|
||||
app.add_config_value('xref_links', {}, True)
|
||||
app.add_role('xref', xref)
|
||||
app.connect("builder-inited", get_refs)
|
||||
|
||||
262
docs/family.rst
|
|
@ -1,262 +0,0 @@
|
|||
A family
|
||||
============
|
||||
|
||||
Synopsis
|
||||
---------
|
||||
|
||||
A family is a container of variables and subfamily.
|
||||
|
||||
.. attention:: A family without a subfamily or subvariable will be automatically deleted.
|
||||
|
||||
Name
|
||||
-------------
|
||||
|
||||
It is with this name that we will be able to interact with the family.
|
||||
|
||||
It's best to follow the :ref:`convention on variable names`.
|
||||
|
||||
Shorthand declaration
|
||||
----------------------------
|
||||
|
||||
Shorthand declaration is a way to declare a family in a single line. But you can only define family name and description.
|
||||
|
||||
To create a family, just add a key with it's name and variables as values. Attention, do not declare any other attributs.
|
||||
|
||||
By default, the description of the variable is the family name.
|
||||
If you add comment in same line of name, this comment is use as description:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
my_family: # This is a great family
|
||||
variable:
|
||||
|
||||
Parameters
|
||||
---------------
|
||||
|
||||
.. FIXME: faire une page sur la "convention on variable names"
|
||||
|
||||
.. list-table::
|
||||
:widths: 15 45
|
||||
:header-rows: 1
|
||||
|
||||
* - Parameter
|
||||
- Comments
|
||||
|
||||
* - type, _type
|
||||
|
||||
`string`
|
||||
|
||||
- possile values:
|
||||
|
||||
- `family` (**default value**)
|
||||
- `leadership`
|
||||
- `dynamic`
|
||||
|
||||
.. note:: If a subfamily or a subvariable already has the name `"type"`, it is possible to use the `"_type"` attribute.
|
||||
|
||||
* - description, _description
|
||||
|
||||
`string`
|
||||
- Description of the family.
|
||||
|
||||
User information to understand the usefulness of the family.
|
||||
|
||||
..note:: If a subfamily or subvariable already has the name "description" it is possible to use the "_description" attribute.
|
||||
|
||||
* - help, _help
|
||||
|
||||
`string`
|
||||
- Additional help associated with the family.
|
||||
|
||||
.. note:: If a subfamily or a subvariable already has the name "help" it is possible to use the "_help" attribute.
|
||||
|
||||
* - mode, _mode
|
||||
|
||||
`string`
|
||||
- Family mode.
|
||||
|
||||
The default mode of a family is the smallest mode of the parent families, child variables, or child families that are contained in that family.
|
||||
|
||||
This mode also allows you to define the default mode for variables or families included in this family.
|
||||
|
||||
.. note:: If a subfamily or a subvariable already has the name "mode" it is possible to add the "_mode" attribute.
|
||||
|
||||
* - hidden, _hidden
|
||||
|
||||
`string`
|
||||
- Invisible family.
|
||||
|
||||
Allows you to hide a family as well as the variables or families included in this family.
|
||||
|
||||
This means that the family will no longer be visible in `read-write` mode, but only for calculations or in `read-only` mode.
|
||||
|
||||
.. note:: If a subfamily or a subvariable already has the name "hidden" it is possible to add the "_hidden" attribute.
|
||||
|
||||
* - disabled, _disabled
|
||||
|
||||
`string`
|
||||
|
||||
- Disabled family.
|
||||
|
||||
Allows you to deactivate a family as well as the variables or families included in this family.
|
||||
|
||||
This means that the family will no longer be visible to the user but also to a :term:`calculation`.
|
||||
|
||||
.. note:: If a subfamily or a subvariable already has the name "disabled" it is possible to use the "_disabled" attribute.
|
||||
|
||||
Dynamically created family
|
||||
-----------------------------
|
||||
|
||||
To create a family dynamically, you must create a fictitious family linked to a calculation.
|
||||
The family name will actually be the prefix of the new name. Alternativly you can specify the suffix in the name, ie `my_{{ suffix }}_name`.
|
||||
The suffix will come from the calculation.
|
||||
|
||||
Obviously if the result of calculation were to evolve, new dynamic families will appear or disappear.
|
||||
|
||||
Leader or follower variable
|
||||
-----------------------------
|
||||
|
||||
A leader family has a typical attribute of “leadership”. The type is required.
|
||||
|
||||
A leader family
|
||||
----------------
|
||||
|
||||
The leader and follower variables are placed in a leader family.
|
||||
|
||||
A leader family cannot contain other families.
|
||||
|
||||
The default mode of the leader family is the mode of the leader variable.
|
||||
|
||||
Leader variable
|
||||
----------------
|
||||
|
||||
A leader variable is a variable that will guide the length of other variables (called follower variables).
|
||||
|
||||
A leader variable is a :doc:`variable` that must have the `multiple` type.
|
||||
|
||||
A leader variable may be mandatory.
|
||||
|
||||
The default mode corresponds to the smallest mode defined for the follower variables.
|
||||
|
||||
Follower variable
|
||||
--------------------
|
||||
|
||||
A follower variable is a variable whose length is not determined by itself, but is identical to that of the leader variable on which it depends.
|
||||
|
||||
A follower variable is a variable placed just behind a leader variable or another follower variable.
|
||||
|
||||
The order in which the tracking variables are defined is important.
|
||||
|
||||
This variable can be of multiple type. In this case, for a determined index of the leading variable, it is possible to put several values to the same variable.
|
||||
|
||||
A follower variable may be required. This means that when a leader variable is entered, the follower variable must also be a value at the index considered. If no value is defined for the leader variable, no value is specified for the follower variable.
|
||||
|
||||
The default mode of a follower variable corresponds to the mode of the leader variable.
|
||||
|
||||
If a leader variable is hidden or disabled, the follower variables will be hidden or disabled as well.
|
||||
|
||||
Examples
|
||||
----------
|
||||
|
||||
Simple family:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
my_family:
|
||||
type: family
|
||||
description: This is a great family
|
||||
help: This is the help of a great family
|
||||
mode: expert
|
||||
|
||||
Dynamically created family
|
||||
----------------------------
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
varname:
|
||||
multi: true
|
||||
default:
|
||||
- val1
|
||||
- val2
|
||||
my_dyn_family_:
|
||||
type: dynamic
|
||||
dynamic:
|
||||
type: variable
|
||||
variable: rougail.varname
|
||||
description: 'Describe'
|
||||
my_dyn_var:
|
||||
type: string
|
||||
description: 'Variable description'
|
||||
|
||||
This will dynamically create two families:
|
||||
|
||||
- "rougail.my_dyn_family_val1"
|
||||
- "rougail.my_dyn_family_val2"
|
||||
|
||||
In the dynamic family "rougail.my_dyn_family_val1" we will find a variable "my_dyn_var".
|
||||
|
||||
Here is a second example:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
varname:
|
||||
multi: true
|
||||
default:
|
||||
- val1
|
||||
- val2
|
||||
my_dyn_{{ suffix }}_family:
|
||||
type: dynamic
|
||||
dynamic:
|
||||
type: variable
|
||||
variable: rougail.varname
|
||||
description: 'Describe'
|
||||
my_dyn_var:
|
||||
type: string
|
||||
description: 'Variable description'
|
||||
|
||||
This will dynamically create two families:
|
||||
|
||||
- "rougail.my_dyn_val1_family"
|
||||
- "rougail.my_dyn_val2_family"
|
||||
|
||||
In the dynamic family "rougail.my_dyn_val1_family" we will find a variable "my_dyn_var".
|
||||
|
||||
Leader or follower variable
|
||||
-------------------------------
|
||||
|
||||
Definition of leader and follower variables
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Here is an example of defining a leading variable and two following variables:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
family:
|
||||
type: leadership
|
||||
leader:
|
||||
multi: true
|
||||
follower1:
|
||||
follower2:
|
||||
multi: true
|
||||
|
||||
Adding a new follower variable
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To add a new follower variable, in a new dictionary, simply define one or more new variables in the leader family:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
family:
|
||||
follower3:
|
||||
585
docs/fill.rst
|
|
@ -1,585 +0,0 @@
|
|||
Calculated default values
|
||||
==============================
|
||||
|
||||
Synopsis
|
||||
-----------
|
||||
|
||||
A value can be calculated. In this case we have four possibilities:
|
||||
|
||||
- calculation via Jinja
|
||||
- calculation via a variable
|
||||
- calculation via information
|
||||
- calculation via a suffix: in the case of a variable in a dynamic family
|
||||
- calculation via an index: in the case of a follower variable
|
||||
|
||||
If the user modifies the value of the variable, the default value is no longer used, so the calculation is no longer carried out. This is also the case if the variable has the `auto_save` attribute.
|
||||
|
||||
On the other hand, if the variable is hidden (with the `hidden` parameter), it is the default value that is used and not the value customized by the user.
|
||||
|
||||
.. note:: A follower variable cannot be calculated automatically.
|
||||
|
||||
Parameters
|
||||
--------------
|
||||
|
||||
Depending on the types of calculation, the parameters will be different:
|
||||
|
||||
.. list-table::
|
||||
:widths: 15 25 20 15
|
||||
:header-rows: 1
|
||||
|
||||
* - Calculation type
|
||||
- Parameter
|
||||
- Comments
|
||||
- Sample
|
||||
|
||||
* -
|
||||
- **type**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
|
||||
- Type of calculation, possible values are: jinja, variable, information, suffix or index
|
||||
- jinja
|
||||
* - Jinja
|
||||
- **jinja**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- Template Jinja. For a multiple variable, each line represents a value.
|
||||
- `{% if rougail.variable %}
|
||||
|
||||
{{ rougail.variable }}
|
||||
|
||||
{% endif %}`
|
||||
* - Jinja
|
||||
- **params**
|
||||
|
||||
`list`
|
||||
- Additional parameters passed to the Jinja template
|
||||
-
|
||||
* - Variable (`mandatory`)
|
||||
|
||||
Information
|
||||
- **variable**
|
||||
|
||||
`string`
|
||||
- Name of associated variable
|
||||
- rougail.variable
|
||||
* - Variable
|
||||
- **propertyerror**
|
||||
|
||||
`boolean`
|
||||
- If access to the variable is not possible due to a property (for example `disabled`) by default an error is returned. If the attribute is `false`, the calculated value is empty.
|
||||
|
||||
**Default value:** `true`
|
||||
- false
|
||||
|
||||
* - Information
|
||||
- **information**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- Name of the information whose value we want to retrieve.
|
||||
- doc
|
||||
|
||||
In the case of a Jinja type calculation, it is possible to have parameters.
|
||||
|
||||
There are two types of parameter:
|
||||
|
||||
- the standard parameters (string, boolean, integer, null), in this case just do: "key: value"
|
||||
|
||||
- the advanced settings:
|
||||
|
||||
- parameter via a variable
|
||||
- parameter via an information
|
||||
- parameter via a suffix: in the case of a variable in a dynamic family
|
||||
- parameter via an index: in the case of a follower variable
|
||||
|
||||
.. list-table::
|
||||
:widths: 15 25 20 15
|
||||
:header-rows: 1
|
||||
|
||||
* - Parameter type
|
||||
- Parameter
|
||||
- Comments
|
||||
- Sample
|
||||
|
||||
* -
|
||||
- **name**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- parameter's name
|
||||
- my_param
|
||||
* -
|
||||
- **type**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- parameter's type, possible values are: variable, information, suffix or index
|
||||
- suffix
|
||||
* - Variable
|
||||
- **variable**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
|
||||
- Variable's name
|
||||
- rougail.variable
|
||||
* - Variable (`mandatory`) information
|
||||
- **propertyerror**
|
||||
|
||||
`boolean`
|
||||
- If access to the variable is not possible due to a property (for example `disabled`) by default an error is returned. If the attribute is `False`, the parameter is not passed to the Jinja template.
|
||||
- **Default value**: `True`
|
||||
* - Variable
|
||||
- **optional**
|
||||
|
||||
`boolean`
|
||||
- The variable may not exist depending on YAML file imports.
|
||||
If the optional parameter is `True`, the parameter will simply be deleted if the variable does not exist.
|
||||
|
||||
Default value : `False`
|
||||
- True
|
||||
* - Information
|
||||
- **information**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- Name of the information whose value we want to retrieve.
|
||||
- doc
|
||||
|
||||
The variable path
|
||||
-----------------
|
||||
|
||||
Normal family
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
The default namespace is defined in RougailConfig["variable_namespace"] with the default value "rougail".
|
||||
In addition, there are extras namespaces defined with in RougailConfig["extra_dictionaries"].
|
||||
|
||||
Inside those namespaces we can add families and variables.
|
||||
|
||||
Here is an hierarchic examples:
|
||||
|
||||
.. code-block::
|
||||
rougail
|
||||
├── variable1
|
||||
├── family1
|
||||
│ ├── variable2
|
||||
│ └── variable3
|
||||
└── family2
|
||||
└── subfamily1
|
||||
└── variable4
|
||||
extra1
|
||||
└── family3
|
||||
├── variable5
|
||||
└── variable6
|
||||
|
||||
In `calculation` we can use other variables.
|
||||
|
||||
Here is all paths:
|
||||
|
||||
- rougail.variable1
|
||||
- rougail.family1.variable2
|
||||
- rougail.family1.variable3
|
||||
- rougail.family2.subfamily1.variable4
|
||||
- extra1.family3.variable5
|
||||
- extra1.family3.variable6
|
||||
|
||||
Inside a variable's `calculation` we can use relative path. "_" means that other variable is in same family. "__" means that other variables are in parent family, and so on...
|
||||
|
||||
For example, in variable2's `calculation`, we can use relative path:
|
||||
|
||||
- __.variable1
|
||||
- _.variable3
|
||||
- __.family2.subfamily1.variable4
|
||||
|
||||
But we cannot access to extra1 variables with relative path.
|
||||
|
||||
Dynamic family
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Hire is a dynamic family "{{ suffix }}":
|
||||
|
||||
.. code-block::
|
||||
rougail
|
||||
├── variable1: ["val1", "val2"]
|
||||
├── {{ suffix }}
|
||||
│ ├── variable2
|
||||
│ └── variable3
|
||||
└── family
|
||||
└── variable4
|
||||
|
||||
For variable2's calculation, we can use:
|
||||
|
||||
- rougail.{{ suffix }}.variable3
|
||||
- _.variable3
|
||||
|
||||
In this case, we get value for "variable3" with the same suffix as "variable2".
|
||||
|
||||
For variable4's calculation, we have two possibility:
|
||||
|
||||
- retrieves all values with all suffixes:
|
||||
|
||||
- rougail.{{ suffix }}.variable3
|
||||
- __.{{ suffix }}.variable3
|
||||
|
||||
- retrieves a value for a specified suffix:
|
||||
|
||||
- rougail.val1.variable3
|
||||
- __.val1.variable3
|
||||
|
||||
Examples
|
||||
-----------
|
||||
|
||||
Calculation via a Jinja template
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Let's start with an example from a simple Jinja template:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
my_calculated_variable:
|
||||
default:
|
||||
type: jinja
|
||||
jinja: 'no'
|
||||
|
||||
Here is a second example with a boolean variable:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
my_calculated_variable:
|
||||
type: boolean
|
||||
default:
|
||||
type: jinja
|
||||
jinja: 'false'
|
||||
|
||||
And a multiple value of the number type:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
my_calculated_variable:
|
||||
type: number
|
||||
multi: true
|
||||
default:
|
||||
type: jinja
|
||||
jinja: |
|
||||
1
|
||||
2
|
||||
3
|
||||
|
||||
Let's create a variable whose value is returned by a python function:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
my_calculated_variable:
|
||||
default:
|
||||
type: jinja
|
||||
jinja: '{{ return_no() }}'
|
||||
|
||||
Then let's create the `return_no` function:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def return_no():
|
||||
return 'no'
|
||||
|
||||
An example with parameters:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
my_calculated_variable:
|
||||
description: my description
|
||||
default:
|
||||
type: jinja
|
||||
jinja: |
|
||||
{{ param1 }}{% if param2 is defined %}_{{ param2 }}{% endif %}_{{ param3 }}
|
||||
params:
|
||||
param1: value
|
||||
param2:
|
||||
type: variable
|
||||
variable: _.unknown_variable
|
||||
optional: true
|
||||
param3:
|
||||
type: information
|
||||
information: doc
|
||||
variable: _.my_calculated_variable
|
||||
|
||||
An example with a `suffix` type parameter:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
varname:
|
||||
multi: true
|
||||
default:
|
||||
- val1
|
||||
- val2
|
||||
my_dyn_family_:
|
||||
type: dynamic
|
||||
dynamic:
|
||||
type: variable
|
||||
variable: _.varname
|
||||
description: 'Describe '
|
||||
my_dyn_var:
|
||||
type: string
|
||||
default:
|
||||
type: jinja
|
||||
jinja: 'the suffix is: {{ param1 }}'
|
||||
params:
|
||||
param1:
|
||||
type: suffix
|
||||
|
||||
In this example, we see a dynamic family. Two families will be created: `rougail.my_dyn_family_val1.my_dyn_var` and `rougail.my_dyn_family_val2.my_dyn_var`.
|
||||
|
||||
The value of the variable inside this family 'this suffix is: ' + the value of the suffix (`val1` and `val2` respectively).
|
||||
|
||||
An example with an index type parameter:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
family:
|
||||
type: leadership
|
||||
leader:
|
||||
multi: true
|
||||
default:
|
||||
- val1
|
||||
- val2
|
||||
follower1:
|
||||
default:
|
||||
type: jinja
|
||||
jinja: 'the index is: {{ param1 }}'
|
||||
params:
|
||||
param1:
|
||||
type: index
|
||||
|
||||
Calculation via a variable
|
||||
-----------------------------
|
||||
|
||||
Copy a variable in another:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
my_variable:
|
||||
multi: true
|
||||
default:
|
||||
- val1
|
||||
- val2
|
||||
my_calculated_variable:
|
||||
multi: true
|
||||
default:
|
||||
type: variable
|
||||
variable: _.my_variable
|
||||
|
||||
Copy the default value from a variable, means copy type, params and multi attribute too if not define in second variable.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: 1.1
|
||||
my_variable:
|
||||
multi: true
|
||||
type: domainname
|
||||
params:
|
||||
allow_ip: true
|
||||
my_calculated_variable:
|
||||
default:
|
||||
type: variable
|
||||
variable: _.var1
|
||||
|
||||
Here my_calculated_variable is a domainname variable with parameter allow_ip=True and multi to true.
|
||||
|
||||
Copy one variable to another if the source has no `property` problem:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
my_variable:
|
||||
default: val1
|
||||
disabled: true
|
||||
my_calculated_variable:
|
||||
multi: true
|
||||
default:
|
||||
type: variable
|
||||
variable: _.my_variable
|
||||
propertyerror: false
|
||||
|
||||
Copy two non-multiple variables into a multiple variable:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
my_variable_1:
|
||||
default: val1
|
||||
my_variable_2:
|
||||
default: val2
|
||||
my_calculated_variable:
|
||||
multi: true
|
||||
default:
|
||||
- type: variable
|
||||
variable: _.my_variable_1
|
||||
- type: variable
|
||||
variable: _.my_variable_2
|
||||
|
||||
A variable in a dynamic family can also be used in a calculation.
|
||||
|
||||
For example using the variable for a particular suffix:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
varname:
|
||||
multi: true
|
||||
default:
|
||||
- val1
|
||||
- val2
|
||||
my_dyn_family_:
|
||||
type: dynamic
|
||||
dynamic:
|
||||
type: variable
|
||||
variable: _.varname
|
||||
description: 'Describe '
|
||||
my_dyn_var_:
|
||||
type: string
|
||||
default:
|
||||
type: suffix
|
||||
all_dyn_var:
|
||||
default:
|
||||
type: variable
|
||||
variable: _.my_dyn_family_val1.my_dyn_var_val1
|
||||
|
||||
In this case, we recover the value `val1`.
|
||||
|
||||
Second example using the variable for all suffixes:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
varname:
|
||||
multi: true
|
||||
default:
|
||||
- val1
|
||||
- val2
|
||||
my_dyn_family_:
|
||||
type: dynamic
|
||||
dynamic:
|
||||
type: variable
|
||||
variable: _.varname
|
||||
description: 'Describe '
|
||||
my_dyn_var_:
|
||||
type: string
|
||||
default:
|
||||
type: suffix
|
||||
all_dyn_var:
|
||||
multi: true
|
||||
default:
|
||||
type: variable
|
||||
variable: _.my_dyn_family_.my_dyn_var_
|
||||
|
||||
In this case, we recover the `val1` and `val2` list.
|
||||
|
||||
Calculation via a suffix
|
||||
---------------------------
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
varname:
|
||||
multi: true
|
||||
default:
|
||||
- val1
|
||||
- val2
|
||||
my_dyn_family_:
|
||||
type: dynamic
|
||||
dynamic:
|
||||
type: variable
|
||||
variable: _.varname
|
||||
description: 'Describe '
|
||||
my_dyn_var_:
|
||||
type: string
|
||||
default:
|
||||
type: suffix
|
||||
|
||||
Calculation via an index
|
||||
--------------------------
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
family:
|
||||
type: leadership
|
||||
leader:
|
||||
multi: true
|
||||
default:
|
||||
- val1
|
||||
- val2
|
||||
follower1:
|
||||
type: number
|
||||
default:
|
||||
type: index
|
||||
|
||||
Redefinition
|
||||
----------------
|
||||
|
||||
In a first dictionary, let's declare our variable and our calculation:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
my_calculated_variable:
|
||||
default:
|
||||
type: jinja
|
||||
jinja: 'the value is calculated'
|
||||
|
||||
In a second dictionary, it is possible to redefine the calculation:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
my_calculated_variable:
|
||||
redefine: true
|
||||
default:
|
||||
type: jinja
|
||||
jinja: 'the value is redefined'
|
||||
|
||||
In a third dictionary, we even can delete the calculation if needed:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
my_calculated_variable:
|
||||
redefine: true
|
||||
default: null
|
||||
|
||||
563
docs/format_content/calculation.rst
Normal file
|
|
@ -0,0 +1,563 @@
|
|||
.. _calculated_variable:
|
||||
|
||||
Calculated default values
|
||||
==============================
|
||||
|
||||
Synopsis
|
||||
-----------
|
||||
|
||||
A value can be calculated. In this case we have four possibilities:
|
||||
|
||||
- calculation via Jinja template
|
||||
- calculation via a variable
|
||||
- calculation via an information
|
||||
- calculation via a identifier: in a :term:`dynamically built family` returns the current identifier
|
||||
- calculation via an index: in the case of a :term:`follower` variable returns the current index
|
||||
- calculation via :ref:`the current namespace name <namespace>`
|
||||
|
||||
If the user modifies the value of the variable, the default value is no longer used, so the calculation is no longer carried out. This is also the case if the variable has the `auto_save` attribute.
|
||||
|
||||
On the other hand, if the variable is hidden (with the `hidden` parameter), it is the default value that is used and not the value customized by the user.
|
||||
|
||||
.. note:: A follower variable cannot be calculated automatically.
|
||||
|
||||
.. seealso:: The tutorial with a real world sample :ref:`calculation <tutorial_calc_variable>`
|
||||
|
||||
Parameters
|
||||
--------------
|
||||
|
||||
Jinja template
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - **Calculation type**
|
||||
- **Comment**
|
||||
|
||||
* - **type**
|
||||
|
||||
`string`
|
||||
- The value is `jinja`
|
||||
|
||||
* - **jinja**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- Please set a Jinja template.
|
||||
|
||||
* - **params**
|
||||
|
||||
`dict`
|
||||
- Additional parameters passed to the Jinja template (see below).
|
||||
|
||||
* - **description**
|
||||
|
||||
`string`
|
||||
- Additional information for the :ref:`documentation <data_documentation>` and the error message in case of return_type is a boolean.
|
||||
|
||||
Variable
|
||||
~~~~~~~~
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Parameter
|
||||
- Comment
|
||||
- Sample
|
||||
|
||||
* - type
|
||||
|
||||
`string`
|
||||
- Calculation type.
|
||||
|
||||
This parameter is optional. It is deduced from the presence of the parameter "variable" in a calculation.
|
||||
- variable
|
||||
|
||||
* - variable
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- Name of the associated variable.
|
||||
|
||||
It's better to use :term:`relative path` notation.
|
||||
- _.my_variable
|
||||
|
||||
* - propertyerror
|
||||
|
||||
`boolean`
|
||||
- If access to the variable is not possible due to a property
|
||||
(for example `disabled`) by default an error is returned.
|
||||
The overall coherence is not guaranteed.
|
||||
|
||||
Default value: `true`
|
||||
- false
|
||||
|
||||
* - optional
|
||||
|
||||
`boolean`
|
||||
- The variable in calculation may not exist. This generates an error. Overall coherence is not guaranteed.
|
||||
To avoid this set the optional parameter to `true`. In this case, if variable in calculation is not exists, the variable is always accessible.
|
||||
- true
|
||||
|
||||
* - default
|
||||
|
||||
`boolean`
|
||||
- If optional parameter is set to `true` and the variable in calculation is not exist, the variable is accessible.
|
||||
If you do not want this behavior, set this parameter to `false`.
|
||||
- false
|
||||
|
||||
* - description
|
||||
|
||||
`string`
|
||||
- Rougail engine create a description like "depends on a calculation".
|
||||
You can personnalize here the calculation description
|
||||
-
|
||||
|
||||
Information
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Parameter
|
||||
- Comments
|
||||
- Sample
|
||||
|
||||
* - information
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- Name of the information whose value we want to retrieve.
|
||||
- doc
|
||||
|
||||
* - variable
|
||||
|
||||
`string`
|
||||
- Variable's name. If not specified, the information is retrieve in :term:`Tiramisu` Config.
|
||||
|
||||
It's better to use :term:`relative path` notation.
|
||||
- _.my_variable
|
||||
|
||||
Params
|
||||
~~~~~~
|
||||
|
||||
In the case of a Jinja type calculation, it is possible to have parameters.
|
||||
|
||||
There are two types of params:
|
||||
|
||||
- the standard parameters (string, boolean, integer, float or null), in this case just do: "key: value"
|
||||
- advanced settings (with something like "key: {}":
|
||||
|
||||
- parameter via a variable
|
||||
- parameter via an information
|
||||
- parameter via an identifier: in a :term:`dynamically built family` returns the current identifier
|
||||
- parameter via an index: in the case of a :term:`follower` variable returns the current index
|
||||
- parameter via :ref:`the current namespace name <namespace>`
|
||||
|
||||
Variable params
|
||||
"""""""""""""""
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - **Parameter**
|
||||
- **Comments**
|
||||
- **Sample**
|
||||
|
||||
* - **type**
|
||||
|
||||
`string`
|
||||
- Type of parameter, which is variable.
|
||||
- variable
|
||||
|
||||
* - **variable**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- Variable's path.
|
||||
- my_variable
|
||||
|
||||
* - **propertyerror**
|
||||
|
||||
`boolean`
|
||||
- If access to the variable is not possible due to a property
|
||||
(for example `disabled`) by default an error is returned.
|
||||
If the attribute is `false`, the parameter is not passed to the Jinja template.
|
||||
|
||||
**Default value**: `false`
|
||||
- `true`
|
||||
|
||||
* - **optional**
|
||||
|
||||
`boolean`
|
||||
- If the variable is not defined the value is always `null`.
|
||||
|
||||
**Default value**: `false`
|
||||
- `true`
|
||||
|
||||
* - **whole**
|
||||
|
||||
`boolean`
|
||||
- In :term:`dynamically built family` only the value of the current index is retrieve. If this parameter is set to `true` it returns all
|
||||
If this parameter is set to `true`, it returns the set of values for all indices.
|
||||
|
||||
**Default value**: `false`
|
||||
- `true`
|
||||
|
||||
Information params
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - **Parameter**
|
||||
- **Comments**
|
||||
- **Sample**
|
||||
|
||||
* - **type**
|
||||
|
||||
`string`
|
||||
- Type of parameter, which is information
|
||||
- information
|
||||
|
||||
* - **information**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- Name of the information whose value we want to retrieve.
|
||||
- doc
|
||||
|
||||
* - **variable**
|
||||
|
||||
`string`
|
||||
- By default, the information is a context information. It is possible to get a variable information. In this case just specify a path.
|
||||
- my_variable
|
||||
|
||||
Sample
|
||||
-----------
|
||||
|
||||
Calculation via a Jinja template
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Let's start with an example from a simple Jinja template:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_calculated_variable:
|
||||
default:
|
||||
jinja: 'no'
|
||||
...
|
||||
|
||||
Here is a second example with a boolean variable:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_calculated_variable:
|
||||
type: boolean
|
||||
default:
|
||||
jinja: 'false'
|
||||
...
|
||||
|
||||
And a multiple value of the integer type:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_calculated_variable:
|
||||
type: integer
|
||||
multi: true
|
||||
default:
|
||||
jinja: |
|
||||
1
|
||||
2
|
||||
3
|
||||
...
|
||||
|
||||
Let's create a variable whose value is returned by a python function:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_calculated_variable:
|
||||
default:
|
||||
jinja: '{{ return_no() }}'
|
||||
...
|
||||
|
||||
Then let's create the `return_no` function:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def return_no():
|
||||
return 'no'
|
||||
|
||||
An example with parameters:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_calculated_variable:
|
||||
description: my description
|
||||
default:
|
||||
jinja: |
|
||||
{{ param1 }}{% if param2 is defined %}_{{ param2 }}{% endif %}_{{ param3 }}
|
||||
params:
|
||||
param1: value
|
||||
param2:
|
||||
type: variable
|
||||
variable: _.unknown_variable
|
||||
optional: true
|
||||
param3:
|
||||
type: information
|
||||
information: doc
|
||||
variable: _.my_calculated_variable
|
||||
...
|
||||
|
||||
An example with a `identifier` type parameter:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_dyn_family_{{ identifier }}:
|
||||
dynamic:
|
||||
- val1
|
||||
- val2
|
||||
description: 'Describe {{ identifier }}'
|
||||
|
||||
my_dyn_var:
|
||||
default:
|
||||
jinja: 'the identifier is: {{ param1 }}'
|
||||
params:
|
||||
param1:
|
||||
type: identifier
|
||||
|
||||
In this example, we see a :term:`dynamically built family`. Two families will be created: `my_dyn_family_val1.my_dyn_var` and `my_dyn_family_val2.my_dyn_var`.
|
||||
|
||||
The value of the variable inside this family 'this identifier is: ' + the value of the identifier (`val1` and `val2` respectively).
|
||||
|
||||
An example with an index type parameter:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
family:
|
||||
type: sequence
|
||||
|
||||
leader:
|
||||
- val1
|
||||
- val2
|
||||
|
||||
follower1:
|
||||
default:
|
||||
type: jinja
|
||||
jinja: 'the index is: {{ param1 }}'
|
||||
params:
|
||||
param1:
|
||||
type: index
|
||||
...
|
||||
|
||||
Calculation via a variable
|
||||
-----------------------------
|
||||
|
||||
Copy a variable in another:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable:
|
||||
default:
|
||||
- val1
|
||||
- val2
|
||||
|
||||
my_calculated_variable:
|
||||
default:
|
||||
type: variable
|
||||
variable: _.my_variable
|
||||
...
|
||||
|
||||
Copy the default value from a variable, means copy type, params and multi attribute too if not define in second variable.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable:
|
||||
multi: true
|
||||
type: domainname
|
||||
params:
|
||||
allow_ip: true
|
||||
|
||||
my_calculated_variable:
|
||||
default:
|
||||
type: variable
|
||||
variable: _.var1
|
||||
|
||||
Here my_calculated_variable is a domainname variable with parameter allow_ip=True and multi to true.
|
||||
|
||||
Copy one variable to another if the source has no `property` problem:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable:
|
||||
default: val1
|
||||
disabled: true
|
||||
|
||||
my_calculated_variable:
|
||||
multi: true
|
||||
default:
|
||||
variable: _.my_variable
|
||||
propertyerror: false
|
||||
...
|
||||
|
||||
Copy two non-multiple variables into a multiple variable:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable_1: val1
|
||||
|
||||
my_variable_2: val2
|
||||
|
||||
my_calculated_variable:
|
||||
default:
|
||||
- variable: _.my_variable_1
|
||||
- variable: _.my_variable_2
|
||||
|
||||
A variable in a :term:`dynamically built family` can also be used in a calculation.
|
||||
|
||||
For example using the variable for a particular identifier:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
varname:
|
||||
- val1
|
||||
- val2
|
||||
|
||||
my_dyn_family_{{ identifier }}:
|
||||
dynamic:
|
||||
- val1
|
||||
- val2
|
||||
description: 'Describe {{ identifier }}'
|
||||
my_dyn_var_{{ identifier }}:
|
||||
default:
|
||||
type: identifier
|
||||
|
||||
all_dyn_var:
|
||||
default:
|
||||
variable: _.my_dyn_family_val1.my_dyn_var_val1
|
||||
|
||||
In this case, we recover the value `val1`.
|
||||
|
||||
Second example using the variable for all identifieres:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
varname:
|
||||
my_dyn_family_{{ identifier }}:
|
||||
dynamic:
|
||||
- val1
|
||||
- val2
|
||||
description: 'Describe {{ identifier }}'
|
||||
|
||||
my_dyn_var_{{ identifier }}:
|
||||
default:
|
||||
type: identifier
|
||||
|
||||
all_dyn_var:
|
||||
multi: true
|
||||
default:
|
||||
variable: _.my_dyn_family_.my_dyn_var_
|
||||
...
|
||||
|
||||
In this case, we recover the `val1` and `val2` list.
|
||||
|
||||
Calculation via a identifier
|
||||
----------------------------
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_dyn_family_{{ identifier }}:
|
||||
dynamic:
|
||||
- val1
|
||||
- val2
|
||||
description: 'Describe {{ identifier }}'
|
||||
|
||||
my_dyn_var_{{ identifier }}:
|
||||
type: string
|
||||
default:
|
||||
type: identifier
|
||||
...
|
||||
|
||||
Calculation via an index
|
||||
--------------------------
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
family:
|
||||
type: sequence
|
||||
|
||||
leader:
|
||||
- val1
|
||||
- val2
|
||||
|
||||
follower1:
|
||||
type: integer
|
||||
default:
|
||||
type: index
|
||||
...
|
||||
276
docs/format_content/condition.rst
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
Calculated properties
|
||||
==========================
|
||||
|
||||
Synopsis
|
||||
------------
|
||||
|
||||
Calculated properties allow you to add or remove properties to a :term:`variable` or a :term:`family` depending on the context.
|
||||
|
||||
Here is the list of editable properties:
|
||||
|
||||
.. list-table::
|
||||
:widths: 15 15 25
|
||||
:header-rows: 1
|
||||
|
||||
* - Attribute applying to
|
||||
- Property's name
|
||||
- Comment
|
||||
|
||||
* - Variable
|
||||
|
||||
Family
|
||||
- hidden
|
||||
- Hides a variable or a family, in this case it is not accessible in `read-write` mode,
|
||||
but remains accessible in a calculation or in `read-only` mode.
|
||||
|
||||
.. seealso:: :ref:`hidden access control <hidden>`.
|
||||
|
||||
* - Variable
|
||||
|
||||
Family
|
||||
- disabled
|
||||
- Deactivates a variable or family, in this case it is never accessible.
|
||||
|
||||
.. seealso:: :ref:`disabled access control <disabled>`.
|
||||
|
||||
* - Variable
|
||||
- frozen
|
||||
- A frozen variable is a variable that the :term:`operator` cannot change the value.
|
||||
|
||||
* - Variable
|
||||
- mandatory
|
||||
- The variable expects a value other than `null` (or `None` in Python) or `[]` for multiple variables.
|
||||
|
||||
.. seealso:: for non multiple variables we call it a :ref:`nullable variable <nullable_variable>`.
|
||||
|
||||
* - Variable
|
||||
- empty
|
||||
- The multiple variable allow the value `null` (or `None` in Python)
|
||||
|
||||
.. seealso:: we call it a :ref:`nullable variable <nullable_variable>`.
|
||||
|
||||
A property can be calculated. In this case we have two possibilities:
|
||||
|
||||
- calculation via Jinja (see also the tutorial with a real world sample :doc:`variable jinja <../tutorial/jinja>`)
|
||||
- calculation via a variable (see also the tutorial with a real world sample :doc:`variable calculation <../tutorial/properties>`)
|
||||
|
||||
Parameters
|
||||
---------------
|
||||
|
||||
Variable parameters
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Parameter
|
||||
- Comment
|
||||
- Sample
|
||||
|
||||
* - type
|
||||
|
||||
`string`
|
||||
- Calculation type.
|
||||
|
||||
This parameter is optional. It is deduced from the presence of the parameter "variable" in a calculation.
|
||||
- variable
|
||||
|
||||
* - variable
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- Name of the associated variable.
|
||||
|
||||
It's better to use :term:`relative path` notation.
|
||||
- _.my_variable
|
||||
|
||||
* - when/when_not
|
||||
- Compare the value of the variable define in `variable` attribute.
|
||||
|
||||
If the related variable is the boolean typed variable, the default value is `true`
|
||||
- See the tutorial with a real world sample :doc:`when_not <../tutorial/properties>`)
|
||||
|
||||
* - propertyerror
|
||||
|
||||
`boolean` or `transitive`
|
||||
- If access to the variable is not possible due to a property
|
||||
(for example `disabled`) by default an error is returned.
|
||||
The overall coherence is not guaranteed.
|
||||
If the parameter is `false`, the calculated value is `false` in this condition.
|
||||
If the parameter is `transitive`, the calculated is `true` if the variable raise propertyerror
|
||||
or `false` otherwise.
|
||||
|
||||
Default value: `true`
|
||||
- transitive
|
||||
|
||||
false
|
||||
|
||||
* - optional
|
||||
|
||||
`boolean`
|
||||
- The variable in calculation may not exist. This generates an error. Overall coherence is not guaranteed.
|
||||
To avoid this set the optional parameter to `true`. In this case, if variable in calculation is not exists, the variable is always accessible.
|
||||
- true
|
||||
|
||||
* - default
|
||||
|
||||
`boolean`
|
||||
- If optional parameter is set to `true` and the variable in calculation is not exist, the variable is accessible.
|
||||
If you do not want this behavior, set this parameter to `false`.
|
||||
- false
|
||||
|
||||
* - description
|
||||
|
||||
`string`
|
||||
- Rougail engine create a description like "when the variable "xxxx" has the value "yyyy".
|
||||
You can personnalize here the calculation description
|
||||
-
|
||||
|
||||
Jinja parameters
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Parameter
|
||||
- Comment
|
||||
- Sample
|
||||
|
||||
* - type
|
||||
|
||||
`string`
|
||||
- The calculation type.
|
||||
|
||||
This parameter is optional. It is deduced from the presence of the parameter "jinja" in calculation.
|
||||
- jinja
|
||||
|
||||
* - jinja
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- Jinja template. For a multiple variable, each line represents a value.
|
||||
|
||||
It's better to use :term:`relative path` notation in Jinja template.
|
||||
- .. code-block:: jinja
|
||||
|
||||
{% if _.my_variable %}
|
||||
{{ _.my_variable }}
|
||||
{% endif %}
|
||||
|
||||
* - params
|
||||
|
||||
`dict`
|
||||
- Additional parameters passed to the Jinja template
|
||||
|
||||
See below to have params possibility.
|
||||
- See the tutorial with a real world sample :doc:`params <../tutorial/jinja>`)
|
||||
|
||||
* - return_type
|
||||
|
||||
`string`
|
||||
- Jinja template could return two type of value:
|
||||
|
||||
- `string` (default): that means the Jinja template return an error message that explain why we don't have access to this variable
|
||||
- `boolean`: the Jinja template return "true" or "false". The value true means that the properties is present.
|
||||
|
||||
- See the tutorial with a real world sample :doc:`return_type <../tutorial/jinja>`)
|
||||
|
||||
* - description
|
||||
|
||||
`string`
|
||||
`recommanded`
|
||||
- Rougail engine cannot deduce what you want to do in Jinja template. You have to describe it for documentation purpose.
|
||||
If return_type parameter is `boolean`, this description is used in error message.
|
||||
- See the tutorial with a real world sample :doc:`description <../tutorial/jinja>`)
|
||||
|
||||
In the case of a Jinja type calculation, it is possible to have parameters (`params`).
|
||||
|
||||
There are two types of parameter:
|
||||
|
||||
- the standard parameters (string, boolean, integer, null), in this case just do: "key: value"
|
||||
|
||||
- advanced settings:
|
||||
|
||||
- parameter via a variable
|
||||
- parameter via information
|
||||
- parameter via an identifier: in the case of a variable in a :term:`dynamically built family`
|
||||
- parameter via an index: in the case of a variable in a :term:`sequence`
|
||||
- parameter via the current :term:`namespace`
|
||||
|
||||
Parameters for variable type `param`
|
||||
''''''''''''''''''''''''''''''''''''
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Parameter
|
||||
- Comments
|
||||
- Sample
|
||||
|
||||
* - type
|
||||
|
||||
`string`
|
||||
- Parameter's type
|
||||
- variable
|
||||
|
||||
* - variable
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- Variable's name
|
||||
|
||||
It's better to use :term:`relative path` notation.
|
||||
- _.my_variable
|
||||
|
||||
* - propertyerror
|
||||
|
||||
`boolean`
|
||||
- If access to the variable is not possible due to a property (for example `disabled`) by default an error is returned. If the parameter is false, the parameter is not passed to the Jinja template.
|
||||
|
||||
Default value: `true`
|
||||
- false
|
||||
|
||||
* - optional
|
||||
|
||||
`boolean`
|
||||
- The variable may not exist depending on YAML file imports. If the optional parameter is true, the parameter will simply be deleted if the variable does not exist.
|
||||
Default value: `false`
|
||||
- true
|
||||
|
||||
* - whole
|
||||
|
||||
`boolean`
|
||||
- In :term:`sequence` family, only the value of the variable in the current element is propose.
|
||||
This parameter allow you to have all values for all elements.
|
||||
|
||||
Default value: `false`.
|
||||
- true
|
||||
|
||||
Parameters for information type `param`
|
||||
'''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Parameter
|
||||
- Comments
|
||||
- Sample
|
||||
|
||||
* - information
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- Name of the information whose value we want to retrieve.
|
||||
- doc
|
||||
|
||||
* - variable
|
||||
|
||||
`string`
|
||||
- Variable's name. If not specified, the information is retrieve in :term:`Tiramisu` Config.
|
||||
|
||||
It's better to use :term:`relative path` notation.
|
||||
- _.my_variable
|
||||
283
docs/format_content/family.rst
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
The families
|
||||
=============
|
||||
|
||||
Synopsis
|
||||
---------
|
||||
|
||||
.. glossary::
|
||||
|
||||
family
|
||||
subfamily
|
||||
|
||||
A family (or a subfamily) is simply a collection of variables that refer to
|
||||
the same business model category. It's just a variables container.
|
||||
Think of it as a container as well as a namespace.
|
||||
|
||||
.. attention:: A family without a subfamily or subvariable will be automatically deleted.
|
||||
|
||||
Naming
|
||||
---------
|
||||
|
||||
It is with its name that we will be able to interact with the family.
|
||||
|
||||
.. seealso::
|
||||
|
||||
A family is a variable. So have a look at the :ref:`variable naming convention <namingconvention>`.
|
||||
|
||||
Parameters
|
||||
---------------
|
||||
|
||||
.. list-table::
|
||||
:widths: 15 45
|
||||
:header-rows: 1
|
||||
|
||||
* - Parameter
|
||||
- Comments
|
||||
|
||||
* - **description**, **_description**
|
||||
|
||||
`string`
|
||||
- Description of the family.
|
||||
|
||||
User information to understand the usefulness of the family.
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`description parameter <../tutorial/family>`
|
||||
|
||||
* - **help**, **_help**
|
||||
|
||||
`string`
|
||||
- Additional help associated with the family.
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`help parameter <../tutorial/document>` (the tutorial focuses on variable, but the principle is the same for a family)
|
||||
|
||||
* - **mode**, **_mode**
|
||||
|
||||
`string`
|
||||
- Family mode.
|
||||
|
||||
The mode is a way of classifying the importance, the level of expertise required, or the access rights to a family.
|
||||
|
||||
This parameter allows you to define the family mode, and also the default mode for variables or families included in this family.
|
||||
|
||||
.. attention:: Mode is not configured by default. You have to define mode level before use this parameter.
|
||||
|
||||
**Default value**: The default mode of a family is the smallest mode of the parent families, child variables, or child families that are contained in that family.
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`mode parameter <../tutorial/mode>` (the tutorial focuses on variable, but the principle is the same for a family)
|
||||
|
||||
* - **type**, **_type**
|
||||
|
||||
`string`
|
||||
- possible values:
|
||||
|
||||
- `family` (**default value**)
|
||||
- `dynamic`
|
||||
- `sequence`
|
||||
|
||||
* - **hidden**, **_hidden**
|
||||
|
||||
`boolean` or :term:`calculation`
|
||||
- Invisible family.
|
||||
|
||||
Enables us to *hide* a family as well as the variables or families included in this family.
|
||||
|
||||
This means that the family will no longer be visible in `read-write` mode, but only for calculations or in `read-only` mode.
|
||||
|
||||
**Default value**: `false`
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`hidden parameter <../tutorial/properties>`
|
||||
|
||||
* - **disabled**, **_disabled**
|
||||
|
||||
`boolean` or :term:`calculation`
|
||||
- Disabled family.
|
||||
|
||||
Allows us to *deactivate* a family as well as the variables or families included in this family.
|
||||
|
||||
This means that the family will no longer be visible to the user but also to a :term:`calculation`.
|
||||
|
||||
**Default value**: `false`
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`disabled parameter <../tutorial/properties>`
|
||||
|
||||
* - **dynamic**, **_dynamic**
|
||||
|
||||
:term:`calculation` or a list of :term:`calculation` or `string`
|
||||
- Dynamic identifiers.
|
||||
|
||||
.. important:: This parameter is only available for dynamically built family. See the explanations about this below.
|
||||
|
||||
* - **redefine**
|
||||
|
||||
`boolean`
|
||||
- It is possible to define a family in one :term:`structure file` and change its behavior in a second :term:`structure file`. In this case you must explicitly redefine the family.
|
||||
|
||||
**Default value**: `false`
|
||||
|
||||
* - **exists**
|
||||
|
||||
`boolean`
|
||||
- This parameter does two things:
|
||||
|
||||
- creates a family if it does not exist in another :term:`structure file` (otherwise do nothing), in this case the value of the parameter must be `true`
|
||||
- in conjunction with the `redefine` parameter set to `true`, only modifies the behavior if it is pre-existing, in which case the parameter's value must be `false`.
|
||||
|
||||
**Default value**: `null`
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
If a subfamily or a subvariable already has the name of a parameter it is possible to use the "_<parameter>" name.
|
||||
You can have a look at the tutorial with a real world sample :doc:`of parameter with "_" <../tutorial/underscore_parameter>`.
|
||||
|
||||
Short-hand declaration
|
||||
----------------------------
|
||||
|
||||
Short-hand declaration is a way to declare a family in a single line.
|
||||
|
||||
To create a family, just add a key with it's name and variables as values:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
my_family:
|
||||
|
||||
my_variable:
|
||||
...
|
||||
|
||||
By default, the description of the family is the family name.
|
||||
It's a best practice to description a family. Just add comment in same line of name, this comment is use as description:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
my_family: # This is a great family
|
||||
|
||||
my_variable:
|
||||
...
|
||||
|
||||
But in short-hand notation, you can only define family name and description.
|
||||
|
||||
.. attention:: Any other parameters will be considered as a variable. Do not use short-hand in this case.
|
||||
|
||||
A family
|
||||
---------
|
||||
|
||||
Here is a simple example:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
my_family:
|
||||
description: This is a great family
|
||||
help: This family is great because we have great variables inside
|
||||
|
||||
my_variable:
|
||||
...
|
||||
|
||||
.. seealso::
|
||||
|
||||
You can have a look at the tutorial with a real world sample:
|
||||
|
||||
- :doc:`family <../tutorial/family>`
|
||||
- :doc:`help parameter <../tutorial/document>` (the tutorial focuses on variable, but the principle is the same for a family)
|
||||
|
||||
A dynamically built family
|
||||
-----------------------------
|
||||
|
||||
To create a :term:`dynamically built family`, you must create a fictitious family linked to a list of uniq identifiers.
|
||||
This list could be hard coded or resulting from a calculation.
|
||||
|
||||
The name of this family is particular. You have to add `{{ identifier }}` string inside. It will be replace by each identifiers.
|
||||
|
||||
Here is an simple example:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_{{ identifier }}_family:
|
||||
description: 'A family for {{ identifier }}'
|
||||
dynamic:
|
||||
- one thing
|
||||
- another
|
||||
|
||||
variable:
|
||||
description: 'A variable for {{ identifier }}'
|
||||
...
|
||||
|
||||
This will dynamically create two families:
|
||||
|
||||
- "my_one_thing_family"
|
||||
- "my_another_family"
|
||||
|
||||
.. seealso::
|
||||
|
||||
You can have a look at the tutorial with a real world sample :doc:`dynamically built family <../tutorial/dynamic>`
|
||||
|
||||
.. _sequence_family:
|
||||
|
||||
Sequence of homogeneous elements
|
||||
---------------------------------------
|
||||
|
||||
A family with `type` set to `sequence` is a sequence of homogeneous elements.
|
||||
|
||||
Let's start the explanation with a concrete example:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
accounts:
|
||||
description: All accounts
|
||||
type: sequence
|
||||
|
||||
login:
|
||||
description: Account login
|
||||
type: unix_user
|
||||
|
||||
secret:
|
||||
description: Account secret
|
||||
type: secret
|
||||
...
|
||||
|
||||
What is expected, it's something like:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
accounts:
|
||||
- login: foo
|
||||
secret: 0hM%G0dW4a7ASecr3t
|
||||
- login: bar
|
||||
secret: NotGoodSecret
|
||||
|
||||
It's what we call a Sequence of homogeneous elements.
|
||||
|
||||
.. attention:: A sequence cannot contain other families.
|
||||
|
||||
.. seealso::
|
||||
|
||||
You can have a look at the tutorial with a real world sample :doc:`Sequence of homogeneous elements <../tutorial/sequence>`
|
||||
|
||||
A custom type family
|
||||
----------------------
|
||||
|
||||
In short, a custom type is nothing more than a kind of a template for a family.
|
||||
Define a custom type family is much like defining families.
|
||||
|
||||
This custom type family can be used as many times as desired and customized as you wish.
|
||||
|
||||
.. seealso::
|
||||
|
||||
You can have a look at the tutorial with a real world sample :doc:`family custom type <../tutorial/family>`
|
||||
18
docs/format_content/index.rst
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
The Rougail format
|
||||
=====================
|
||||
|
||||
Now that we understand what can be described in a structured data file, let's see how to describe variables.
|
||||
|
||||
The variable is described in Rougail format.
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
:caption: Rougail format content
|
||||
|
||||
variable
|
||||
family
|
||||
path
|
||||
mutability
|
||||
calculation
|
||||
condition
|
||||
validation
|
||||
114
docs/format_content/mutability.rst
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
.. _redefine:
|
||||
|
||||
Redefine a variable
|
||||
===================
|
||||
|
||||
We have already introduced the concept of :ref:`variable mutability <variable_mutability>`.
|
||||
To summarize, an :term:`integrator` allows the :ref:`structured data <structured_data>` to evolve at any time.
|
||||
|
||||
.. glossary::
|
||||
|
||||
redefine
|
||||
|
||||
A redefine is a redefinition of all or part of the parameters of a variable as it was previously defined.
|
||||
|
||||
.. seealso::
|
||||
|
||||
See the tutorial with a real world sample :ref:`redefine <tutorial_redefine>`.
|
||||
|
||||
Explicit redefine
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
The redefinition is explicit.
|
||||
This means that if an :term:`integrator` defines the same tree twice for two variables, Rougail will consider that there is a naming conflict.
|
||||
|
||||
To illustrate, we could create two :term:`structure files <structure file>`:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable: # A description
|
||||
...
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable: # A redefined description
|
||||
...
|
||||
|
||||
And the name conflict is detected:
|
||||
|
||||
.. code-block:: bash
|
||||
:class: terminal
|
||||
|
||||
$ rougail -m variable.yml redefine.yml
|
||||
ERROR: variable "my_variable" define multiple time in "variable.yml" and "redefine.yml"
|
||||
|
||||
So we have to explicit redefine a variable like this:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable:
|
||||
redefine: true
|
||||
description: A redefined description
|
||||
...
|
||||
|
||||
Now we can see that the redefinition is correct:
|
||||
|
||||
.. code-block:: bash
|
||||
:class: terminal
|
||||
|
||||
$rougail -m variable.yml redefine.yml -o doc
|
||||
┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ Variable ┃ Description ┃
|
||||
┡━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||
│ my_variable │ A redefined description. │
|
||||
│ string mandatory │ │
|
||||
└─────────────────────┴──────────────────────────┘
|
||||
|
||||
The new description has been taken into account.
|
||||
|
||||
Unify
|
||||
~~~~~
|
||||
|
||||
When redefining a variable, we define the list of parameters that we wish to redefine.
|
||||
|
||||
In other words the variable is unify (combine) from multiple variables declarations.
|
||||
|
||||
The old parameters that were present before the redefinition are still present.
|
||||
|
||||
If we modify the `redefine.yml` :term:`structure file`:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable:
|
||||
redefine: true
|
||||
type: integer
|
||||
...
|
||||
|
||||
.. code-block:: bash
|
||||
:class: terminal
|
||||
|
||||
$ rougail -m variable.yml redefine.yml -o doc
|
||||
┏━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓
|
||||
┃ Variable ┃ Description ┃
|
||||
┡━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━┩
|
||||
│ my_variable │ A description. │
|
||||
│ integer mandatory │ │
|
||||
└──────────────────────┴────────────────┘
|
||||
|
||||
Here we can see that the variable has the original description, but the new type.
|
||||
69
docs/format_content/path.rst
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
|
||||
.. index:: path, variable's relative path, variable's full path
|
||||
|
||||
.. _variablepath:
|
||||
|
||||
Full or relative path
|
||||
=====================
|
||||
|
||||
To access a variable, it is necessary to know which family or subfamily it belongs to.
|
||||
|
||||
Let's create some variables to illustrate this point.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_family: # A family
|
||||
|
||||
my_sub_family: # A family inside an other family
|
||||
|
||||
my_first_variable: # My first variable
|
||||
|
||||
my_second_variable: # My second variable
|
||||
|
||||
my_third_variable: # My third variable
|
||||
|
||||
my_fourth_variable: # My forth variable
|
||||
...
|
||||
|
||||
So we have three variables.
|
||||
|
||||
Here the full paths are:
|
||||
|
||||
- `my_family.my_sub_family.my_first_variable`
|
||||
- `my_family.my_sub_family.my_second_variable`
|
||||
- `my_family.my_third_variable`
|
||||
- `my_fourth_variable`
|
||||
|
||||
But in calculation it's often better to use :term:`relative path`.
|
||||
|
||||
.. glossary::
|
||||
|
||||
relative path
|
||||
|
||||
In a calculation definition, a relative path defines the location of a variable relative to the family of the variable where the parameter is calculated.
|
||||
Instead of starting from the root, it uses references like `_. (current family)`, `__. (parent family)`, `___. (sub parent family)` and so on.
|
||||
|
||||
Relative paths are shorter and portable across custom type.
|
||||
|
||||
Now we can define the :term:`relative path` from the `my_first_variable` variable:
|
||||
|
||||
- `_.my_second_variable`
|
||||
- `__.my_third_variable`
|
||||
- `___.my_fourth_variable`
|
||||
|
||||
From the `my_third_variable`:
|
||||
|
||||
- `_.my_sub_family.my_first_variable`
|
||||
- `_.my_sub_family.my_second_variable`
|
||||
- `__.my_fourth_variable`
|
||||
|
||||
Finally from the `my_fourth_variable`:
|
||||
|
||||
- `_.my_family.my_sub_family.my_first_variable`
|
||||
- `_.my_family.my_sub_family.my_second_variable`
|
||||
- `_.my_family.my_third_variable`
|
||||
|
||||
303
docs/format_content/validation.rst
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
Value validations
|
||||
=================
|
||||
|
||||
Synopsis
|
||||
-------------
|
||||
|
||||
A verification is a complementary validation to the type which allows the content of a variable to be validated more precisely.
|
||||
|
||||
The purpose of validation is to verify that the variable is of :ref:`good quality <data_quality>` and/or that the variable is :ref:`consistent <consistency>`.
|
||||
|
||||
.. glossary::
|
||||
|
||||
validator
|
||||
|
||||
A validator is a Jinja code that parses a variable's value and checks
|
||||
that this value corresponds to some stated criteria.
|
||||
This is a `validator` parameter of our variable, and another `jinja` sub-parameter
|
||||
contains validation code for the variable's value.
|
||||
|
||||
.. seealso:: The tutorial with a real world sample :ref:`validators <tutorial_validators>`
|
||||
|
||||
Parameters
|
||||
--------------
|
||||
|
||||
Depending on the types of calculation, the parameters will be different:
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - **Calculation type**
|
||||
- **Comment**
|
||||
|
||||
* - **type**
|
||||
|
||||
`string`
|
||||
- The value is `jinja`
|
||||
|
||||
* - **jinja**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- Please set a Jinja template.
|
||||
|
||||
* - **params**
|
||||
|
||||
`dict`
|
||||
- Additional parameters passed to the Jinja template (see below).
|
||||
|
||||
* - **return_type**
|
||||
|
||||
`string`
|
||||
- A validation could returns the error message directly, so return_type is `string` (the default behavior).
|
||||
Or a `boolean`, in this case if it's return `true` this means that the value is not valid.
|
||||
|
||||
* - **description**
|
||||
|
||||
`string`
|
||||
- Additional information for the :ref:`documentation <data_documentation>` and the error message in case of return_type is a boolean.
|
||||
|
||||
* - **warnings**
|
||||
|
||||
`boolean`
|
||||
- If `true` the validation did not raise, it only display a warning.
|
||||
|
||||
|
||||
Params
|
||||
~~~~~~
|
||||
|
||||
There are two types of params:
|
||||
|
||||
- the standard parameters (string, boolean, integer, float or null), in this case just do: "key: value"
|
||||
- advanced settings (with something like "key: {}":
|
||||
|
||||
- parameter via a variable
|
||||
- parameter via an information
|
||||
- parameter via an identifier: in a :ref:`dynamically built family` returns the current identifier
|
||||
- parameter via an index: in the case of a :term:`follower` variable returns the current index
|
||||
- parameter via :ref:`the current namespace name <namespace>`
|
||||
|
||||
Variable params
|
||||
"""""""""""""""
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - **Parameter**
|
||||
- **Comments**
|
||||
- **Sample**
|
||||
|
||||
* - **type**
|
||||
|
||||
`string`
|
||||
- Type of parameter, which is variable.
|
||||
- variable
|
||||
|
||||
* - **variable**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- Variable's path.
|
||||
- rougail.variable
|
||||
|
||||
* - **propertyerror**
|
||||
|
||||
`boolean`
|
||||
- If access to the variable is not possible due to a property
|
||||
(for example `disabled`) by default an error is returned.
|
||||
If the attribute is `false`, the parameter is not passed to the Jinja template.
|
||||
|
||||
**Default value**: `false`
|
||||
- `true`
|
||||
|
||||
* - **optional**
|
||||
|
||||
`boolean`
|
||||
- If the variable is not defined the value is always `null`.
|
||||
|
||||
**Default value**: `false`
|
||||
- `true`
|
||||
|
||||
* - **whole**
|
||||
|
||||
`boolean`
|
||||
- In :term:`dynamically built family` only the value of the current index is retrieve. If this parameter is set to `true` it returns all
|
||||
If this parameter is set to `true`, it returns the set of values for all indices.
|
||||
|
||||
**Default value**: `false`
|
||||
- `true`
|
||||
|
||||
Information params
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - **Parameter**
|
||||
- **Comments**
|
||||
- **Sample**
|
||||
|
||||
* - **type**
|
||||
|
||||
`string`
|
||||
- Type of parameter, which is information
|
||||
- information
|
||||
|
||||
* - **information**
|
||||
|
||||
`string`
|
||||
|
||||
`mandatory`
|
||||
- Name of the information whose value we want to retrieve.
|
||||
- doc
|
||||
|
||||
* - **variable**
|
||||
|
||||
`string`
|
||||
- By default, the information is a context information. It is possible to get a variable information. In this case just specify a path.
|
||||
- rougail.variable
|
||||
|
||||
Samples
|
||||
--------------
|
||||
|
||||
Strict verification of values
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Here is a simple example of validating values:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable:
|
||||
validators:
|
||||
- jinja: |-
|
||||
{% if my_variable is not none and not my_variable.islower() %}
|
||||
{{ my_variable }} is not lowercase string
|
||||
{% endif %}
|
||||
...
|
||||
|
||||
A verification function must take into account 2 important aspects:
|
||||
|
||||
- the value may not be entered (even if the variable is mandatory), the None value must be taken into account
|
||||
- if return_type is `string` and the value is invalid, a sentence must be returned with an explicit message.
|
||||
|
||||
From now on only `null` and lowercase values will be allowed.
|
||||
|
||||
Checking values with warning
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In the constraint, it is possible to specify the error level and put it as a warning:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable:
|
||||
validators:
|
||||
- jinja: |-
|
||||
{% if my_variable is not none and not my_variable.islower() %}
|
||||
{{ my_variable }} is not lowercase string
|
||||
{% endif %}
|
||||
params:
|
||||
warnings: true
|
||||
...
|
||||
|
||||
In this case a value with a capital letter will be accepted, but a warning message will appear.
|
||||
|
||||
Verification with parameters
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_hidden_variable:
|
||||
disabled: true
|
||||
|
||||
my_variable:
|
||||
validators:
|
||||
- type: jinja
|
||||
jinja: |-
|
||||
{% if param1 is defined and my_variable == param1 %}
|
||||
has same value as unknown_variable
|
||||
{% endif %}
|
||||
{% if param2 is defined and my_variable == param2 %}
|
||||
has same value as my_hidden_variable
|
||||
{% endif %}
|
||||
params:
|
||||
param1:
|
||||
variable: unknown_variable
|
||||
optional: true
|
||||
param2:
|
||||
variable: my_hidden_variable
|
||||
propertyerror: false
|
||||
...
|
||||
|
||||
An example with an identifier type parameter:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_dyn_family_{{ identifier }}:
|
||||
type: dynamic
|
||||
dynamic:
|
||||
- val1
|
||||
- val2
|
||||
description: 'Describe {{ identifier }}'
|
||||
|
||||
my_dyn_var:
|
||||
validators:
|
||||
- jinja: |
|
||||
{% if my_dyn_family_.my_dyn_var == param1 %}
|
||||
forbidden!
|
||||
{% endif %}
|
||||
params:
|
||||
param1:
|
||||
type: identifier
|
||||
...
|
||||
|
||||
In this example, we see a :term:`dynamically built family`. Two families will be created: `my_dyn_family_val1.my_dyn_var` and `my_dyn_family_val2.my_dyn_var`.
|
||||
|
||||
The value of the variable within this family cannot be equal to the value
|
||||
of the identifier (`val1` and `val2` respectively).
|
||||
|
||||
An example with an index type parameter:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
family:
|
||||
type: sequence
|
||||
|
||||
leader:
|
||||
default:
|
||||
- val1
|
||||
- val2
|
||||
|
||||
follower1:
|
||||
type: integer
|
||||
validators:
|
||||
- type: jinja
|
||||
jinja: |-
|
||||
{% if family.follower1 == param1 %}
|
||||
forbidden!
|
||||
{% endif %}
|
||||
params:
|
||||
param1:
|
||||
type: index
|
||||
...
|
||||
608
docs/format_content/variable.rst
Normal file
|
|
@ -0,0 +1,608 @@
|
|||
.. _variable:
|
||||
|
||||
The variables
|
||||
==============
|
||||
|
||||
Synopsis
|
||||
---------
|
||||
|
||||
.. glossary::
|
||||
|
||||
variable
|
||||
|
||||
A variable is an abstract black box (container) paired with an associated symbolic name, most often an option configuration, which contains some defined or undefined data setting referred to as a :term:`value`.
|
||||
|
||||
value
|
||||
|
||||
A value is a variable's setting.
|
||||
Variable can have a default value, that is a setting defined in the :term:`structure file`,
|
||||
or no value at all, then the value needs to be defined later by the :term:`operator`.
|
||||
|
||||
.. discussion:: Discussion
|
||||
|
||||
The variable is, by definition, strongly typed.
|
||||
Rougail uses static type definition and even type inference.
|
||||
Indeed, the constistency handling system heavyly relies on the type system definition.
|
||||
Variables may only be able to store a specified data type.
|
||||
OK, variables are the containers for storing the values. It has something to do with typing.
|
||||
|
||||
But consitency handling system is is not just about strong typing. It is more than that.
|
||||
|
||||
.. _namingconvention:
|
||||
|
||||
Names
|
||||
------
|
||||
|
||||
It is with its name that we will be able to interact with the variable.
|
||||
|
||||
The name of a variable must be chosen carefully.
|
||||
It is the path that will allow users to retrieve their defined values.
|
||||
An obscure name will cause confusion.
|
||||
|
||||
By design, you cannot use just any character to name your variable.
|
||||
|
||||
The regular expression that validates our variable and family naming policy is:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
re.compile(r"^[a-z0-9_]*$")
|
||||
|
||||
You can see that it is mandatory to only use lowercase ASCII letters, numbers and the `"_"` (undescore) character.
|
||||
The snake case typographic convention is therefore used.
|
||||
|
||||
.. attention:: The name must not starts with `_` character.
|
||||
|
||||
Parameters
|
||||
-------------
|
||||
|
||||
.. list-table::
|
||||
:widths: 15 45
|
||||
:header-rows: 1
|
||||
|
||||
* - Parameter
|
||||
- Comments
|
||||
|
||||
* - **description**
|
||||
|
||||
`string`
|
||||
- Description of the variable.
|
||||
|
||||
User information to understand the usefulness of the variable.
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`description parameter <../tutorial/preliminary>`
|
||||
|
||||
* - **help**
|
||||
|
||||
`string`
|
||||
- Additional help associated with the variable.
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`help parameter <../tutorial/document>`
|
||||
|
||||
* - **mode**
|
||||
|
||||
`string`
|
||||
- Variable's mode.
|
||||
|
||||
The mode is a way of classifying the importance, the level of expertise required, or the access rights to a variable.
|
||||
|
||||
This parameter allows you to define the variable mode.
|
||||
|
||||
.. attention:: Mode is not configured by default. You have to define mode level before use this parameter.
|
||||
|
||||
**Default value**: The `default` mode of a variable is the mode of the parent family, but there is special cases:
|
||||
|
||||
- a variable with an automatically modified value or an automatic read-only variable is by default in the smaller mode
|
||||
- if the variable is not in a family, the variable will have a medium mode by default
|
||||
- a :term:`mandatory` variable without default value (calculate or not) will have the smaller mode
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`mode parameter <../tutorial/mode>`
|
||||
|
||||
* - **tags**
|
||||
|
||||
`list of strings`
|
||||
- A tag allows you to specialize a variable.
|
||||
|
||||
A tag can have several functions:
|
||||
|
||||
- Additional information in the documentation
|
||||
- Variable exclusion
|
||||
- Variable selection
|
||||
- and so on
|
||||
|
||||
* - **examples**
|
||||
|
||||
`list`
|
||||
- List of examples to illustrate possible values for a variable
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`examples parameter <../tutorial/document>`
|
||||
|
||||
* - **test**
|
||||
|
||||
`list`
|
||||
- The `test` parameter is a special parameter that allows :term:`structure file` designers to influence a test robot by specifying useful values to test.
|
||||
|
||||
Concretely, the content of this parameter is recorded in the `information` parameter of the corresponding `Tiramisu` option object.
|
||||
|
||||
* - **type**
|
||||
|
||||
`string`
|
||||
- Type of the variable.
|
||||
|
||||
See the list of available type below.
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`type parameter <../tutorial/types>`
|
||||
|
||||
* - **params**
|
||||
|
||||
`object`
|
||||
- Parameters to adjust type validation of the variable.
|
||||
|
||||
See the list of available parameters for each type below.
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`params parameter <../tutorial/types>`
|
||||
|
||||
* - **multi**
|
||||
|
||||
`boolean`
|
||||
|
||||
- The value of the variable is a list.
|
||||
|
||||
**Default value**: mostly `false`, but there is special cases:
|
||||
|
||||
- the default value is a list
|
||||
- a variable with a variable :term:`multiple <multi>` has default value
|
||||
|
||||
It possible to adjust multi parameters with **params**:
|
||||
|
||||
- multi_length: number of expected values for a multiple variable
|
||||
- multi_min_length: maximum number of expected values for a multiple variable
|
||||
- multi_max_length: minimum number of expected values for a minimum variable
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`multi parameter <../tutorial/multiple>`
|
||||
|
||||
* - **validators**
|
||||
|
||||
`list`
|
||||
- Value validators.
|
||||
|
||||
The value of the variable will be considered invalid if the Jinja template return an error.
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`validators parameter <../tutorial/validators>`
|
||||
|
||||
* - **default**
|
||||
- Default value(s) of the variable.
|
||||
|
||||
This value is typed, you must correctly fill out the YAML file to avoid defining a value with an incorrect type. For example, a `integer` must be a digit type, a :term:`multiple <multi>` variable must be a `list` type, ...
|
||||
|
||||
For a non :term:`leading` :term:`multiple <multi>` variable, the first value defined in the list will also be the default value proposed if a new value is added to this variable.
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`default parameter <../tutorial/preliminary>`
|
||||
|
||||
* - **secret_manager**
|
||||
- The variable use a secret manager to get value
|
||||
.. todo:: document it
|
||||
|
||||
* - **auto_save**
|
||||
|
||||
`boolean`
|
||||
- Variable with automatically modified value.
|
||||
|
||||
A variable with automatically modified value is a variable whose value will be considered as *modified* (that is, it is no longer the variable's default value).
|
||||
|
||||
For example, if the value of this variable comes from a calculation, the value will no longer be recalculated.
|
||||
|
||||
These variables are usually :term:`required` variables. In fact, these variables are only automatically modified if they have a value.
|
||||
|
||||
**Default value**: `false`
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`auto_save parameter <../tutorial/autosave>`
|
||||
|
||||
* - **mandatory**
|
||||
|
||||
`boolean` or :term:`calculation`
|
||||
- Mandatory variable.
|
||||
|
||||
Variable whose value is `required`.
|
||||
|
||||
For a :term:`multiple <multi>` variable, this means that the list shall not be empty (means `null` (`None`) or empty list for a i:term:`multiple <multi>`).
|
||||
|
||||
**Default value**: `true`
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`mandatory parameter <../tutorial/nullable>`
|
||||
|
||||
* - **empty**
|
||||
|
||||
`boolean` or :term:`calculation`
|
||||
- The value `null` (`None`) is not allowed in :term:`multiple <multi>` variable.
|
||||
|
||||
The `mandatory` control only if the length :term:`multiple <multi>` variable is not 0. But the `null` value is not allowed. With empty parameter we can allowed it.
|
||||
|
||||
If `null` is an appropriate value, set empty: false.
|
||||
|
||||
**Default value**: `true`
|
||||
|
||||
* - **unique**
|
||||
|
||||
`boolean`
|
||||
- The :term:`multiple <multi>` variable accepts the same value several times.
|
||||
|
||||
If unique is set to `false`, a :term:`multiple <multi>` variable only accepts the same value once in the list.
|
||||
|
||||
**Default value**: `false`
|
||||
|
||||
* - **hidden**
|
||||
|
||||
`boolean` or :term:`calculation`
|
||||
- Invisible variable.
|
||||
|
||||
Enables us to *hide* a variable.
|
||||
|
||||
This means that the variable will no longer be visible in `read-write` mode, but only for calculations or in `read-only` mode.
|
||||
|
||||
When a variable is made invisible, the user will not be able to modify its value; if he has already succeeded in modifying it, this value will not be taken into account.
|
||||
|
||||
**Default value**: `false`
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`hidden parameter <../tutorial/properties>` (the tutorial focuses on family, but the principle is the same for a variable)
|
||||
|
||||
* - **disabled**
|
||||
|
||||
`boolean` or :term:`calculation`
|
||||
- Disabled variable.
|
||||
|
||||
Allows us to *deactivate* a variable.
|
||||
|
||||
This means that the variable will no longer be visible to the user but also to a :term:`calculation`.
|
||||
|
||||
**Default value**: `false`
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`disabled parameter <../tutorial/properties>` (the tutorial focuses on family, but the principle is the same for a variable)
|
||||
|
||||
* - **frozen**
|
||||
|
||||
`boolean` or :term:`calculation`
|
||||
- Read only variable.
|
||||
|
||||
Enables us to have an immutable variable's value.
|
||||
|
||||
This means that the variable will be visible but user will not allowed to change the value.
|
||||
|
||||
**Default value**: `false`
|
||||
|
||||
|
||||
* - **redefine**
|
||||
|
||||
`boolean`
|
||||
- It is possible to define a variable in one :term:`structure file` and change its behavior in a second :term:`structure file`. In this case you must explicitly redefine the variable.
|
||||
|
||||
**Default value**: `false`
|
||||
|
||||
* - **exists**
|
||||
|
||||
`boolean`
|
||||
- This parameter does two things:
|
||||
|
||||
- creates a variable if it does not exist in another :term:`structure file` (otherwise do nothing), in this case the value of the parameter must be `true`
|
||||
- in conjunction with the `redefine` parameter set to `true`, only modifies the behavior if it is pre-existing, in which case the parameter's value must be `false`.
|
||||
|
||||
**Default value**: `null`
|
||||
|
||||
* - **choices**
|
||||
|
||||
:term:`calculation` or a list of :term:`calculation` or data
|
||||
- Available choices.
|
||||
|
||||
.. important:: This parameter is only available for variable with `choice` type.
|
||||
|
||||
* - **regexp**
|
||||
|
||||
`string`
|
||||
- Validation with a regular expressions.
|
||||
|
||||
.. important:: This parameter is only available for variable with `regexp` type.
|
||||
|
||||
Short-hand declaration
|
||||
----------------------------
|
||||
|
||||
Short-hand declaration is a way to declare a variable in a condenced number of line.
|
||||
|
||||
To create a variable, just add a key with it's name:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable:
|
||||
...
|
||||
|
||||
You can add a default value:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable: my_value
|
||||
...
|
||||
|
||||
Or a multi default value:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable:
|
||||
- my_value_1
|
||||
- my_value_2
|
||||
...
|
||||
|
||||
By default, the description of the variable is the variable name.
|
||||
It's a good practice to describe a variable. Just add comment in same line of name, this comment is used as description:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable: my_value # This is a great variable
|
||||
...
|
||||
|
||||
But in short-hand notation, you can only define variable name, default value, multi and description.
|
||||
|
||||
.. attention:: Any other parameters will create extra variables or families
|
||||
|
||||
..
|
||||
.. .. glossary::
|
||||
..
|
||||
.. short-hand notation
|
||||
..
|
||||
.. A short-hand notation in Rougail is the ability to define a variable in
|
||||
.. a short-hand way, there are several example:
|
||||
..
|
||||
.. - a default value:
|
||||
..
|
||||
.. .. code-block:: yaml
|
||||
..
|
||||
.. my_var: true
|
||||
..
|
||||
.. instead of:
|
||||
..
|
||||
.. .. code-block:: yaml
|
||||
..
|
||||
.. my_var:
|
||||
.. default: true
|
||||
|
||||
|
||||
Variable's types
|
||||
-----------------
|
||||
|
||||
A variable **always has a type**. The system is **strongly** typed.
|
||||
|
||||
Depending on the definition of the variable type, the defined variable will accept values of the associated type.
|
||||
|
||||
Primitive Types
|
||||
'''''''''''''''''''
|
||||
|
||||
.. list-table::
|
||||
:widths: 15 25 20 15
|
||||
:header-rows: 1
|
||||
|
||||
* - Value
|
||||
- Comments
|
||||
- Parameters
|
||||
- Samples
|
||||
|
||||
* - string
|
||||
- character string (default type)
|
||||
-
|
||||
- example
|
||||
|
||||
"1"
|
||||
|
||||
"true"
|
||||
|
||||
* - integer
|
||||
- a integer
|
||||
- `min_integer`: minimum integer allowed (unlimited by default)
|
||||
|
||||
`max_integer`: maximum integer allowed (unlimited by default)
|
||||
- 42
|
||||
|
||||
* - float
|
||||
- a floating number
|
||||
-
|
||||
- 1.42
|
||||
|
||||
* - boolean
|
||||
- A boolean, if no value is defined the default value of this variable will be `true`, the variable will also be :term:`mandatory` by default
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`boolean type variable <../tutorial/types>`
|
||||
-
|
||||
- `true`
|
||||
|
||||
`false`
|
||||
|
||||
Specialized type
|
||||
''''''''''''''''''
|
||||
|
||||
.. list-table::
|
||||
:widths: 5 45 45 5
|
||||
:header-rows: 1
|
||||
|
||||
* - Value
|
||||
- Comments
|
||||
- Parameters
|
||||
- Samples
|
||||
|
||||
* - secret
|
||||
- a secret (like a password, a private key, etc.)
|
||||
|
||||
.. seealso:: tutorial with a real world sample :ref:`secret type variable <tutorial_redefine>`
|
||||
- `min_len`: minimum characters length for the secret (unlimited by default)
|
||||
|
||||
`max_len`: maximum characters length for the secret (unlimited by default)
|
||||
|
||||
`forbidden_char`: forbidden characters (no character default)
|
||||
- `hO_'hi`
|
||||
|
||||
* - mail
|
||||
- a mail address
|
||||
-
|
||||
- test@rougail.example
|
||||
|
||||
* - unix_filename
|
||||
- a file name in the Unix meaning
|
||||
- `allow_relative`: this filename could be a relative path (`false` by default)
|
||||
|
||||
`test_existence`: this file must exist (`false` by default)
|
||||
|
||||
`types`: "file type allowed ("file", "directory")
|
||||
- :file:`/etc/passwd`
|
||||
|
||||
* - date
|
||||
- a date in the format `%Y-%m-%d`
|
||||
-
|
||||
- `2021-01-30`
|
||||
|
||||
* - unix_user
|
||||
- a user in the Unix meaning
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`unix type variable <../tutorial/redefine>`
|
||||
-
|
||||
- test
|
||||
|
||||
* - ip
|
||||
- any kind of IPv4 address
|
||||
- `private_only`: only private IPs (`false` by default)
|
||||
|
||||
`allow_reserved`: allows reserved IPs (`true` by default)
|
||||
|
||||
`cidr`: IP must be in CIDR format (`false` by default)
|
||||
- `1.2.3.4`
|
||||
|
||||
* - netmask
|
||||
- mask of an IPv4 address
|
||||
-
|
||||
- `255.255.255.0`
|
||||
|
||||
* - network
|
||||
- network address
|
||||
- `cidr`: network must be in CIDR format (`false` by default)
|
||||
|
||||
`private_only`: private network are allowed (`false` by default)
|
||||
|
||||
`allow_reserved`: reserved network are allowed (`false` by default)
|
||||
- `192.168.1.0`
|
||||
|
||||
* - broadcast
|
||||
- broadcast address
|
||||
-
|
||||
- `1.1.1.255`
|
||||
|
||||
* - domainname
|
||||
- domain name
|
||||
- `type`: type of domain name (`domainname` (by default), `netbios`, `hostname`)
|
||||
|
||||
`allow_ip`: the domain name can be an IP (`false` by default)
|
||||
|
||||
`allow_cidr_network`: the domain name can be network in CIDR format (`false` by default)
|
||||
|
||||
`allow_without_dot`: the domain name can be a hostname (`false` by default)
|
||||
|
||||
`allow_startswith_dot`: the domain name can starts by a dot (`false` by default)
|
||||
|
||||
`test_existence`: the domain name must exist (`false` by default)
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`domainname type variable <../tutorial/types>` or :doc:`a more complet domainname type variable <../tutorial/multiple>`
|
||||
- `rougail.example`
|
||||
|
||||
* - web_address
|
||||
- web address
|
||||
- `type`: type of domain name (`domainname` (by default), `netbios`, `hostname`)
|
||||
|
||||
`allow_ip`: the domain name can be an IP (`false` by default)
|
||||
|
||||
`allow_cidr_network`: the domain name can be network in CIDR format (`false` by default)
|
||||
|
||||
`allow_without_dot`: the domain name can be a hostname (`false` by default)
|
||||
|
||||
`allow_startswith_dot`: the domain name can starts by a dot (`false` by default)
|
||||
|
||||
`test_existence`: the domain name must exist (`false` by default)
|
||||
|
||||
`allow_range`: can be range of port, for example 80:85 (`false` by default)
|
||||
|
||||
`allow_zero`: port 0 is allowed (false by default)
|
||||
|
||||
`allow_wellknown`: well-known ports (1 to 1023) are allowed (`true` by default)
|
||||
|
||||
`allow_registred`: registred ports (1024 to 49151) are allowed (`true` by default)
|
||||
|
||||
`allow_private`: private ports (greater than 49152) are allowed (`false` by default)
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`web_address type variable <../tutorial/webaddress>`
|
||||
- http://rougail.example
|
||||
|
||||
* - port
|
||||
- port
|
||||
- `allow_range`: can be range of port, for example 80:85 (`false` by default)
|
||||
|
||||
`allow_zero`: port 0 is allowed (false by default)
|
||||
|
||||
`allow_wellknown`: well-known ports (1 to 1023) are allowed (`true` by default)
|
||||
|
||||
`allow_registred`: registred ports (1024 to 49151) are allowed (`true` by default)
|
||||
|
||||
`allow_private`: private ports (greater than 49152) are allowed (`false` by default)
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`port type variable <../tutorial/types>`
|
||||
- 8080
|
||||
|
||||
* - mac
|
||||
- MAC address
|
||||
-
|
||||
- 11:11:11:11:11:11
|
||||
|
||||
* - unix_permissions
|
||||
- access rights to the file, directory, etc.
|
||||
-
|
||||
- 644
|
||||
|
||||
* - choice
|
||||
- available choices
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`choice type variable <../tutorial/choice>`
|
||||
-
|
||||
-
|
||||
|
||||
* - regexp
|
||||
- Validation with a regular expressions
|
||||
|
||||
.. seealso:: tutorial with a real world sample :ref:`regexp type variable <tutorial_regexp>`
|
||||
-
|
||||
- r"^#(?:[0-9a-f]{3}){1,2}$"
|
||||
|
||||
Default type
|
||||
''''''''''''''
|
||||
|
||||
If the `type` parameter is not set, Rougail has to define a logical type to valid correctly values:
|
||||
|
||||
- if `choices` or `regexp` parameter is set, Rougail will set the `choice` or `regexp` type
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`choice deducted type <../tutorial/choice>` or :ref:`regexp deducted type <tutorial_regexp>`
|
||||
|
||||
- if a default value is define, Rougail will infers default value type and set a primitive type to the variable
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`type inference <../tutorial/types>`
|
||||
|
||||
- if a variable calculation is define as default value, Rougail copy the type
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`type copying <../tutorial/calculated>`
|
||||
|
||||
- the default type is `string`
|
||||
|
|
@ -1,191 +0,0 @@
|
|||
.. |Tiramisu| replace:: Tiramisu
|
||||
.. _tiramisu: https://forge.cloud.silique.fr/stove/tiramisu
|
||||
|
||||
Getting started
|
||||
====================
|
||||
|
||||
What is a consistency handling system ?
|
||||
------------------------------------------------
|
||||
|
||||
.. questions:: Question: "OK, I have understood that the Rougail stuff enables me to take advantage of |Tiramisu|. But what is all this for? What is exactly a consistency handling system? And again, what is this |Tiramisu| library used for?"
|
||||
|
||||
*Answer*: Well, let's explain what |Tiramisu| is and how we are using the |Tiramisu| library.
|
||||
|
||||
.. glossary::
|
||||
|
||||
Tiramisu
|
||||
|
||||
|Tiramisu| is a consistency handling system that has initially been designed
|
||||
in the configuration management scope. To put it more simply,
|
||||
this library is generally used to handle configuration options.
|
||||
|
||||
It manages variables and group of variables. In the Tiramisu scope we call
|
||||
it *options* and *option descriptions*.
|
||||
|
||||
In the Rougail scope, we call it :term:`variable`\ s and :term:`families`.
|
||||
In Rougail, the families and variables are located in the :term:`dictionaries`.
|
||||
|
||||
And this is what we are going to explain in this page.
|
||||
|
||||
The dictionaries
|
||||
---------------------
|
||||
|
||||
.. glossary::
|
||||
|
||||
dictionary
|
||||
dictionaries
|
||||
|
||||
A dictionary in the Rougail meaning is a YAML file that describes variables
|
||||
and their dependencies / consistencies.
|
||||
There can be a lot of dictionary files located in many different folders.
|
||||
|
||||
Rougail reads all the dictionaries and loads them into a single object
|
||||
that handles the variables consistency.
|
||||
|
||||
.. image:: images/schema.png
|
||||
|
||||
The main advantage is that declaring variables and writing consistency is as simple
|
||||
as writing YAML. With Rougail it is not necessary to write :term:`Tiramisu` code any more.
|
||||
It simplifies a lot of things.
|
||||
|
||||
And rather than writing :term:`Tiramisu` code, we can declare variables and describe the relationships between variables in a declarative mode (that is, in a YAML file).
|
||||
|
||||
Once the dictionaries are loaded by Rougail, we find all the power of the :term:`Tiramisu` configuration management tool.
|
||||
|
||||
The YAML dictionaries format
|
||||
-----------------------------
|
||||
|
||||
Before getting started with Rougail we need to learn the specifics of the YAML dictionaries file format (as well as some templating concepts).
|
||||
|
||||
.. FIXME parler de jinja https://jinja.palletsprojects.com
|
||||
|
||||
Here is a :term:`dictionary` example:
|
||||
|
||||
.. code-block:: yaml
|
||||
:linenos:
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
proxy:
|
||||
description: Configure Proxy Access to the Internet
|
||||
type: family
|
||||
|
||||
Line 3, we declare a **variable** named `proxy` with his `description` line 4 and his `type` line 5.
|
||||
|
||||
The variables
|
||||
-----------------
|
||||
|
||||
variable
|
||||
|
||||
Here is a second definition of a :term:`variable`: it is a declaration unit that represents a business domain metaphor,
|
||||
the most common example is that a variable that represents a configuration option
|
||||
in a application, but a variable represents something more that a configuration option.
|
||||
It provides a business domain specific representation unit.
|
||||
|
||||
.. note:: Dictionaries can just define a list of variables, but we will see that
|
||||
we can specify a lot more. We can define variables **and** their relations,
|
||||
**and** the consistency between them.
|
||||
|
||||
In the next step, we will explain through a tutorial how to construct a list of variables.
|
||||
|
||||
Families of variables
|
||||
--------------------------
|
||||
|
||||
.. glossary::
|
||||
|
||||
family
|
||||
families
|
||||
|
||||
A family of variables is simply a collection of variables that refer to
|
||||
the same business model category. It's just a variables container.
|
||||
Think of it as a container as well as a namespace.
|
||||
|
||||
A "hello world" with Rougail
|
||||
------------------------------
|
||||
|
||||
We're gonna make the simplest possible example.
|
||||
|
||||
.. prerequisites:: Prerequisites
|
||||
|
||||
We assume that Rougail's library is installed on your computer (or in a virtual environment).
|
||||
|
||||
.. exercise:: Let's make a Hello world
|
||||
|
||||
Here is the tree structure we want to have::
|
||||
|
||||
workplace
|
||||
├── dict
|
||||
│ ├── hello.yml
|
||||
└── hello.py
|
||||
|
||||
- Let's make a :file:`workplace` directory, with a :file:`dict` subfolder.
|
||||
- First, we need a :term:`dictionary`, so let's make the :file:`hello.yml` file
|
||||
which is located in the :file:`dict` subfolder, with the following content:
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: The `hello.yaml` file
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
hello:
|
||||
default: world
|
||||
|
||||
- Then we make a :file:`hello.py` in our root :file:`workplace` directory:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: The :file:`hello.py` file
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
|
||||
RougailConfig['dictionaries_dir'] = ['dict']
|
||||
rougail = Rougail()
|
||||
config = rougail.get_config()
|
||||
print(config.value.get())
|
||||
|
||||
.. demo:: Let's run the :file:`hello.py` script
|
||||
|
||||
We launch the script:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
python hello.py
|
||||
|
||||
And we obtain the following result:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
{'rougail.hello': 'world'}
|
||||
|
||||
**Congratulations ! You have successfully completed your first Rougail script.**
|
||||
|
||||
A "Hello, <name> " sample with a family
|
||||
------------------------------------------
|
||||
|
||||
Let's continuing on our "Hello world" theme and add a :term:`family` container.
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: the :file:`hello.yml` file
|
||||
:linenos:
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
world:
|
||||
description: Hello world family container
|
||||
name:
|
||||
description: Somebody to say hello
|
||||
default: rougail
|
||||
|
||||
Here, we have a family named `world`.
|
||||
This family contains a variable named `name`
|
||||
|
||||
Again, let's validate this YAML file against Rougail's API:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
python hello.py
|
||||
|
||||
We then have the output:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
{'rougail.world.name': 'rougail'}
|
||||
72
docs/helper_prerequisites.py
Executable file
|
|
@ -0,0 +1,72 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Génère une section de documentation "prerequisites" pour un tutoriel Rougail,
|
||||
en utilisant une plage de versions (tags git) spécifiée en arguments.
|
||||
|
||||
Usage:
|
||||
python helper_prerequisites.py <start_version> <end_version> <branch>
|
||||
|
||||
Arguments:
|
||||
start_version (str) : La version de début (tag git) pour la plage de tags.
|
||||
end_version (str) : La version de fin (tag git) pour la plage de tags.
|
||||
branch (str) : La branche du dépôt git à mentionner dans la documentation.
|
||||
|
||||
Exemple:
|
||||
|
||||
./helper_prerequisites.py v1.1_080 v1.1_085 1.1
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
def generate_prerequisites(start_version: str, end_version: str, branch: str) -> str:
|
||||
"""
|
||||
Génère une section de documentation "prerequisites" pour une plage de versions donnée.
|
||||
|
||||
Args:
|
||||
start_version (str): La version de début (tag git) pour la plage.
|
||||
end_version (str): La version de fin (tag git) pour la plage.
|
||||
branch (str): La branche du dépôt git à mentionner.
|
||||
|
||||
Returns:
|
||||
str: La section de documentation formatée.
|
||||
"""
|
||||
template = """.. prerequisites:: Prerequisites
|
||||
|
||||
- We assume that Rougail's library is :ref:`installed <installation>` on your computer.
|
||||
|
||||
- It is possible to retrieve the current state of the various Rougail files manipulated in this tutorial step
|
||||
by checking out the corresponding tag of the `rougail-tutorials` git repository.
|
||||
Each tag corresponds to a stage of progress in the tutorial.
|
||||
Of course, you can also decide to copy/paste or download the tutorial files contents while following the tutorial steps.
|
||||
|
||||
If you want to follow this tutorial with the help of the corresponding :tutorial:`rougail-tutorials git repository <src/branch/{branch}>`,
|
||||
this workshop page corresponds to the tags :tutorial:`{start_version} <src/tag/{start_version}/README.md>` to :tutorial:`{end_version} <src/tag/{end_version}/README.md>`
|
||||
in the repository.
|
||||
|
||||
::
|
||||
|
||||
git clone https://forge.cloud.silique.fr/stove/rougail-tutorials.git
|
||||
git switch --detach {start_version}
|
||||
"""
|
||||
return template.format(
|
||||
start_version=start_version,
|
||||
end_version=end_version,
|
||||
branch=branch
|
||||
)
|
||||
|
||||
def main() -> None:
|
||||
"""Point d'entrée principal du script."""
|
||||
if len(sys.argv) != 4:
|
||||
print("Erreur : Trois arguments doivent être spécifiés : <start_version> <end_version> <branch>.")
|
||||
print(f"Usage: {sys.argv[0]} <start_version> <end_version> <branch>")
|
||||
sys.exit(1)
|
||||
|
||||
start_version = sys.argv[1]
|
||||
end_version = sys.argv[2]
|
||||
branch = sys.argv[3]
|
||||
print(generate_prerequisites(start_version, end_version, branch))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
47
docs/helper_type_along.py
Executable file
|
|
@ -0,0 +1,47 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Génère une section de documentation "type-along" pour un tutoriel,
|
||||
en utilisant une version spécifiée en argument.
|
||||
|
||||
Usage:
|
||||
python generate_type_along.py <version>
|
||||
|
||||
Arguments:
|
||||
version (str) : La version (tag git) à utiliser dans la documentation.
|
||||
|
||||
Exemple:
|
||||
python generate_type_along.py v1.0.0
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
def generate_type_along(version: str) -> str:
|
||||
"""
|
||||
Génère une section de documentation "type-along" pour une version donnée.
|
||||
|
||||
Args:
|
||||
version (str): La version (tag git) à inclure dans la documentation.
|
||||
|
||||
Returns:
|
||||
str: La section de documentation formatée.
|
||||
"""
|
||||
template = """.. type-along:: For those who follow the tutorial with the help of the git repository
|
||||
|
||||
Now you need to checkout the :tutorial:`{version} <src/tag/{version}/README.md>` version::
|
||||
|
||||
git switch --detach {version}
|
||||
"""
|
||||
return template.format(version=version)
|
||||
|
||||
def main() -> None:
|
||||
"""Point d'entrée principal du script."""
|
||||
if len(sys.argv) != 2:
|
||||
print("Erreur : Une version doit être spécifiée en argument.")
|
||||
print(f"Usage: {sys.argv[0]} <version>")
|
||||
sys.exit(1)
|
||||
|
||||
version = sys.argv[1]
|
||||
print(generate_type_along(version))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
BIN
docs/images/QuestionaryChoice.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
docs/images/UserDataOutput.png
Normal file
|
After Width: | Height: | Size: 83 KiB |
BIN
docs/images/dessin.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
385
docs/images/dessin.svg
Normal file
|
|
@ -0,0 +1,385 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg width="193.10428mm" height="95.232437mm" viewBox="0 0 193.10428 95.232437" version="1.1" id="svg1" inkscape:version="1.3 (0e150ed6c4, 2023-07-21)" sodipodi:docname="dessin.svg" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview id="namedview1" pagecolor="#ffffff" bordercolor="#000000" borderopacity="0.25" inkscape:showpageshadow="2" inkscape:pageopacity="0.0" inkscape:pagecheckerboard="0" inkscape:deskcolor="#d1d1d1" inkscape:document-units="mm" inkscape:zoom="1.0141844" inkscape:cx="400.32169" inkscape:cy="305.17134" inkscape:window-width="1920" inkscape:window-height="1011" inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="1" inkscape:current-layer="layer1" showgrid="false"/>
|
||||
<defs id="defs1">
|
||||
<linearGradient id="swatch41" inkscape:swatch="solid">
|
||||
<stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop41"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="swatch40" inkscape:swatch="solid">
|
||||
<stop style="stop-color:#175131;stop-opacity:0.53333297;" offset="0" id="stop40"/>
|
||||
</linearGradient>
|
||||
<clipPath id="SVGID_36_-3">
|
||||
<path id="use19-6" d="m 76,96 h 20 c 0.55,0 1,0.45 1,1 v 5 c 0,0.55 -0.45,1 -1,1 H 76 c -0.55,0 -1,-0.45 -1,-1 v -5 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_34_-9">
|
||||
<path id="use18-7" d="m 44,84 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_32_-2-5-5-6-8">
|
||||
<path id="use17-8-5-2-8-9" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_32_-2-5-5-6">
|
||||
<path id="use17-8-5-2-8" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_32_-2-5-5">
|
||||
<path id="use17-8-5-2" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_32_-2-5">
|
||||
<path id="use17-8-5" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_32_-2">
|
||||
<path id="use17-8" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_30_-9">
|
||||
<path id="use16-2" d="m 57,57 h 26 c 0.55,0 1,0.45 1,1 v 1 c 0,0.55 -0.45,1 -1,1 H 57 c -0.55,0 -1,-0.45 -1,-1 v -1 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_4_-7">
|
||||
<path id="use2-5" d="m 28,14 c 1.1,0 2,0.9 2,2 0,1.1 -0.9,2 -2,2 -1.1,0 -2,-0.9 -2,-2 0,-1.1 0.9,-2 2,-2 m -6,0 c 1.1,0 2,0.9 2,2 0,1.1 -0.9,2 -2,2 -1.1,0 -2,-0.9 -2,-2 0,-1.1 0.9,-2 2,-2 m -6,0 c 1.1,0 2,0.9 2,2 0,1.1 -0.9,2 -2,2 -1.1,0 -2,-0.9 -2,-2 0,-1.1 0.9,-2 2,-2 m 2,10 h 104 c 2.21,0 4,1.79 4,4 v 122 c 0,2.21 -1.79,4 -4,4 H 18 c -2.21,0 -4,-1.79 -4,-4 V 28 c 0,-2.21 1.79,-4 4,-4"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_2_-2">
|
||||
<path id="use1-3" d="m 14,8 h 112 c 2.21,0 4,1.79 4,4 v 142 c 0,2.21 -1.79,4 -4,4 H 14 c -2.21,0 -4,-1.79 -4,-4 V 12 c 0,-2.21 1.79,-4 4,-4"/>
|
||||
</clipPath>
|
||||
<linearGradient xlink:href="#E" y2="25.1" x2="86.82" y1="14.793" x1="98.330002" gradientTransform="matrix(0.4888535,0,0,0.4888535,-1.1248979,28.529571)" gradientUnits="userSpaceOnUse" id="I"/>
|
||||
<linearGradient id="E">
|
||||
<stop id="Z"/>
|
||||
<stop offset="1" id="a" stop-color="#ddd" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
<radialGradient xlink:href="#D" id="H" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,0.97467889,0,0.43910718)" cx="89.510002" cy="22.254" r="18.278999"/>
|
||||
<linearGradient id="D">
|
||||
<stop id="X"/>
|
||||
<stop offset="1" id="Y" stop-opacity="0.536"/>
|
||||
</linearGradient>
|
||||
<filter id="F" x="-0.14513263" width="1.2902653" y="-0.17041424" height="1.3408285">
|
||||
<feGaussianBlur stdDeviation="1.81881" id="b"/>
|
||||
</filter>
|
||||
<path id="path11" d="m 14,8 h 112 c 2.21,0 4,1.79 4,4 v 142 c 0,2.21 -1.79,4 -4,4 H 14 c -2.21,0 -4,-1.79 -4,-4 V 12 c 0,-2.21 1.79,-4 4,-4"/>
|
||||
<path id="path12" d="m 28,14 c 1.1,0 2,0.9 2,2 0,1.1 -0.9,2 -2,2 -1.1,0 -2,-0.9 -2,-2 0,-1.1 0.9,-2 2,-2 m -6,0 c 1.1,0 2,0.9 2,2 0,1.1 -0.9,2 -2,2 -1.1,0 -2,-0.9 -2,-2 0,-1.1 0.9,-2 2,-2 m -6,0 c 1.1,0 2,0.9 2,2 0,1.1 -0.9,2 -2,2 -1.1,0 -2,-0.9 -2,-2 0,-1.1 0.9,-2 2,-2 m 2,10 h 104 c 2.21,0 4,1.79 4,4 v 122 c 0,2.21 -1.79,4 -4,4 H 18 c -2.21,0 -4,-1.79 -4,-4 V 28 c 0,-2.21 1.79,-4 4,-4"/>
|
||||
<path id="path13" d="m 57,57 h 26 c 0.55,0 1,0.45 1,1 v 1 c 0,0.55 -0.45,1 -1,1 H 57 c -0.55,0 -1,-0.45 -1,-1 v -1 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<path id="path14" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<path id="path21" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<path id="path22" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<path id="path23" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<path id="path24" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<path id="path15" d="m 44,84 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<path id="path16" d="m 76,96 h 20 c 0.55,0 1,0.45 1,1 v 5 c 0,0.55 -0.45,1 -1,1 H 76 c -0.55,0 -1,-0.45 -1,-1 v -5 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<clipPath id="SVGID_36_-3-7">
|
||||
<path id="use19-6-2" d="m 76,96 h 20 c 0.55,0 1,0.45 1,1 v 5 c 0,0.55 -0.45,1 -1,1 H 76 c -0.55,0 -1,-0.45 -1,-1 v -5 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_34_-9-2">
|
||||
<path id="use18-7-6" d="m 44,84 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_32_-2-5-5-6-8-1">
|
||||
<path id="use17-8-5-2-8-9-0" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_32_-2-5-5-6-6">
|
||||
<path id="use17-8-5-2-8-1" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_32_-2-5-5-5">
|
||||
<path id="use17-8-5-2-9" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_32_-2-5-4">
|
||||
<path id="use17-8-5-9" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_32_-2-0">
|
||||
<path id="use17-8-9" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_30_-9-1">
|
||||
<path id="use16-2-7" d="m 57,57 h 26 c 0.55,0 1,0.45 1,1 v 1 c 0,0.55 -0.45,1 -1,1 H 57 c -0.55,0 -1,-0.45 -1,-1 v -1 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_4_-7-7">
|
||||
<path id="use2-5-1" d="m 28,14 c 1.1,0 2,0.9 2,2 0,1.1 -0.9,2 -2,2 -1.1,0 -2,-0.9 -2,-2 0,-1.1 0.9,-2 2,-2 m -6,0 c 1.1,0 2,0.9 2,2 0,1.1 -0.9,2 -2,2 -1.1,0 -2,-0.9 -2,-2 0,-1.1 0.9,-2 2,-2 m -6,0 c 1.1,0 2,0.9 2,2 0,1.1 -0.9,2 -2,2 -1.1,0 -2,-0.9 -2,-2 0,-1.1 0.9,-2 2,-2 m 2,10 h 104 c 2.21,0 4,1.79 4,4 v 122 c 0,2.21 -1.79,4 -4,4 H 18 c -2.21,0 -4,-1.79 -4,-4 V 28 c 0,-2.21 1.79,-4 4,-4"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_2_-2-1">
|
||||
<path id="use1-3-5" d="m 14,8 h 112 c 2.21,0 4,1.79 4,4 v 142 c 0,2.21 -1.79,4 -4,4 H 14 c -2.21,0 -4,-1.79 -4,-4 V 12 c 0,-2.21 1.79,-4 4,-4"/>
|
||||
</clipPath>
|
||||
<radialGradient xlink:href="#D" id="H-7" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,0.97467889,0,0.43910718)" cx="89.510002" cy="22.254" r="18.278999"/>
|
||||
<filter id="F-3" x="-0.14513263" width="1.2902653" y="-0.17041424" height="1.3408285">
|
||||
<feGaussianBlur stdDeviation="1.81881" id="b-6"/>
|
||||
</filter>
|
||||
<path id="path11-9" d="m 14,8 h 112 c 2.21,0 4,1.79 4,4 v 142 c 0,2.21 -1.79,4 -4,4 H 14 c -2.21,0 -4,-1.79 -4,-4 V 12 c 0,-2.21 1.79,-4 4,-4"/>
|
||||
<path id="path12-5" d="m 28,14 c 1.1,0 2,0.9 2,2 0,1.1 -0.9,2 -2,2 -1.1,0 -2,-0.9 -2,-2 0,-1.1 0.9,-2 2,-2 m -6,0 c 1.1,0 2,0.9 2,2 0,1.1 -0.9,2 -2,2 -1.1,0 -2,-0.9 -2,-2 0,-1.1 0.9,-2 2,-2 m -6,0 c 1.1,0 2,0.9 2,2 0,1.1 -0.9,2 -2,2 -1.1,0 -2,-0.9 -2,-2 0,-1.1 0.9,-2 2,-2 m 2,10 h 104 c 2.21,0 4,1.79 4,4 v 122 c 0,2.21 -1.79,4 -4,4 H 18 c -2.21,0 -4,-1.79 -4,-4 V 28 c 0,-2.21 1.79,-4 4,-4"/>
|
||||
<path id="path13-5" d="m 57,57 h 26 c 0.55,0 1,0.45 1,1 v 1 c 0,0.55 -0.45,1 -1,1 H 57 c -0.55,0 -1,-0.45 -1,-1 v -1 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<path id="path14-8" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<path id="path21-0" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<path id="path22-3" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<path id="path23-1" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<path id="path24-1" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<path id="path15-3" d="m 44,84 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<path id="path16-9" d="m 76,96 h 20 c 0.55,0 1,0.45 1,1 v 5 c 0,0.55 -0.45,1 -1,1 H 76 c -0.55,0 -1,-0.45 -1,-1 v -5 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<clipPath id="SVGID_32_-2-5-4-8">
|
||||
<path id="use17-8-5-9-0" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_32_-2-5-5-5-2">
|
||||
<path id="use17-8-5-2-9-1" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_32_-2-5-5-6-6-0">
|
||||
<path id="use17-8-5-2-8-1-5" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_32_-2-5-5-6-8-1-1">
|
||||
<path id="use17-8-5-2-8-9-0-1" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<path id="path25-6" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<path id="path26-6" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<path id="path27-4" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<path id="path28-0" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<clipPath id="SVGID_32_-2-5-4-8-9">
|
||||
<path id="use17-8-5-9-0-6" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<path id="path31-0" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<clipPath id="SVGID_32_-2-5-4-8-9-4">
|
||||
<path id="use17-8-5-9-0-6-6" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<path id="path35-6" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<clipPath id="SVGID_32_-2-5-4-8-7">
|
||||
<path id="use17-8-5-9-0-5" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_32_-2-5-5-5-2-3">
|
||||
<path id="use17-8-5-2-9-1-5" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_32_-2-5-5-6-6-0-6">
|
||||
<path id="use17-8-5-2-8-1-5-2" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_32_-2-5-5-6-8-1-1-9">
|
||||
<path id="use17-8-5-2-8-9-0-1-1" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_32_-2-5-4-8-9-2">
|
||||
<path id="use17-8-5-9-0-6-7" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_32_-2-5-4-8-9-4-0">
|
||||
<path id="use17-8-5-9-0-6-6-9" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<path id="path31-2" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<path id="path32-2" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<path id="path33-9" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<path id="path34-3" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<path id="path35-7" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<path id="path36-1" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<clipPath id="SVGID_32_-2-5-4-8-9-2-7">
|
||||
<path id="use17-8-5-9-0-6-7-6" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<clipPath id="SVGID_32_-2-5-4-8-9-4-0-5">
|
||||
<path id="use17-8-5-9-0-6-6-9-6" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<path id="path37-5" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
<path id="path38-3" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</defs>
|
||||
<g inkscape:label="Calque 1" inkscape:groupmode="layer" id="layer1" transform="translate(-7.0377231,-10.610595)">
|
||||
<g id="g4" transform="translate(-5.6304861,-28.146403)"/>
|
||||
<path d="m 75.27743,20.804335 v 64.528856 l 52.02464,0.0605 v -47.115 L 110.38375,20.864782 Z" id="2-3" fill="url(#J)" style="fill:#dde5e8;fill-opacity:1;stroke-width:0.56543" sodipodi:nodetypes="cccccc"/>
|
||||
<path id="4-9" d="m 81.698039,28.309502 0.135161,-8.351 C 81.901124,13.359407 80.956142,8.4107397 77.785779,3.9471419 L 80.362343,3.9159389 107.86271,29.53084 c -4.06802,-2.645393 -9.621189,-0.791242 -16.861906,-1.025606 z" transform="matrix(0.57452474,0,0,0.62889423,64.678003,19.231894)" opacity="0.505" fill="url(#H)" filter="url(#F)" style="fill:url(#H-7);filter:url(#F-3)"/>
|
||||
<path d="m 113.61061,34.021794 0.0739,-4.566784 c 0.0372,-3.608745 -1.5219,-6.127035 -3.25563,-8.567976 l 16.88755,17.295457 c -2.22462,-1.44664 -4.65895,-3.925495 -8.61858,-4.053658 z" id="5-4" fill="#eeeeee" style="stroke-width:0.56543"/>
|
||||
<g id="g3-1" transform="matrix(0.43241056,0,0,0.42753179,132.1273,17.754822)">
|
||||
<defs id="defs2-2">
|
||||
<path id="path17" d="m 14,8 h 112 c 2.21,0 4,1.79 4,4 v 142 c 0,2.21 -1.79,4 -4,4 H 14 c -2.21,0 -4,-1.79 -4,-4 V 12 c 0,-2.21 1.79,-4 4,-4"/>
|
||||
</defs>
|
||||
<clipPath id="clipPath3-3">
|
||||
<path id="use3-9" d="m 14,8 h 112 c 2.21,0 4,1.79 4,4 v 142 c 0,2.21 -1.79,4 -4,4 H 14 c -2.21,0 -4,-1.79 -4,-4 V 12 c 0,-2.21 1.79,-4 4,-4"/>
|
||||
</clipPath>
|
||||
<polyline class="st0" points="5,3 135,3 135,163 5,163 5,3 " clip-path="url(#SVGID_2_-2-1)" id="polyline1-0" style="fill:#b8c5d0"/>
|
||||
</g>
|
||||
<g id="g2-8" transform="matrix(0.43241056,0,0,0.42753179,132.1273,17.754822)" style="fill:#dde5e8;fill-opacity:1">
|
||||
<defs id="defs3-8">
|
||||
<path id="path18" d="m 28,14 c 1.1,0 2,0.9 2,2 0,1.1 -0.9,2 -2,2 -1.1,0 -2,-0.9 -2,-2 0,-1.1 0.9,-2 2,-2 m -6,0 c 1.1,0 2,0.9 2,2 0,1.1 -0.9,2 -2,2 -1.1,0 -2,-0.9 -2,-2 0,-1.1 0.9,-2 2,-2 m -6,0 c 1.1,0 2,0.9 2,2 0,1.1 -0.9,2 -2,2 -1.1,0 -2,-0.9 -2,-2 0,-1.1 0.9,-2 2,-2 m 2,10 h 104 c 2.21,0 4,1.79 4,4 v 122 c 0,2.21 -1.79,4 -4,4 H 18 c -2.21,0 -4,-1.79 -4,-4 V 28 c 0,-2.21 1.79,-4 4,-4"/>
|
||||
</defs>
|
||||
<clipPath id="clipPath4-0">
|
||||
<path id="use4-9" d="m 28,14 c 1.1,0 2,0.9 2,2 0,1.1 -0.9,2 -2,2 -1.1,0 -2,-0.9 -2,-2 0,-1.1 0.9,-2 2,-2 m -6,0 c 1.1,0 2,0.9 2,2 0,1.1 -0.9,2 -2,2 -1.1,0 -2,-0.9 -2,-2 0,-1.1 0.9,-2 2,-2 m -6,0 c 1.1,0 2,0.9 2,2 0,1.1 -0.9,2 -2,2 -1.1,0 -2,-0.9 -2,-2 0,-1.1 0.9,-2 2,-2 m 2,10 h 104 c 2.21,0 4,1.79 4,4 v 122 c 0,2.21 -1.79,4 -4,4 H 18 c -2.21,0 -4,-1.79 -4,-4 V 28 c 0,-2.21 1.79,-4 4,-4"/>
|
||||
</clipPath>
|
||||
<polyline class="st1" points="9,9 131,9 131,159 9,159 9,9 " clip-path="url(#SVGID_4_-7-7)" id="polyline2-6" style="fill:#dde5e8;fill-opacity:1"/>
|
||||
</g>
|
||||
<g id="g18-7-0" transform="matrix(0.43241056,0,0,0.42753179,71.62709,6.6686612)" style="fill:#89969f;fill-opacity:1">
|
||||
<defs id="defs17-6-3">
|
||||
<path id="path25" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</defs>
|
||||
<clipPath id="clipPath6-6-44">
|
||||
<path id="use6-9-4" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<rect x="38" y="67" class="st16" width="64" height="16" clip-path="url(#SVGID_32_-2-5-4)" id="rect17-3-4" style="fill:#89969f;fill-opacity:1"/>
|
||||
</g>
|
||||
<g id="g18-7-4-7" transform="matrix(0.43241056,0,0,0.42753179,71.638205,10.446004)" style="fill:#89969f;fill-opacity:1">
|
||||
<defs id="defs17-6-7-6">
|
||||
<path id="path26" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</defs>
|
||||
<clipPath id="clipPath6-6-4-1">
|
||||
<path id="use6-9-3-7" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<rect x="38" y="67" class="st16" width="64" height="16" clip-path="url(#SVGID_32_-2-5-5-5)" id="rect17-3-0-5" style="fill:#89969f;fill-opacity:1"/>
|
||||
</g>
|
||||
<g id="g18-7-4-4-9" transform="matrix(0.43241056,0,0,0.42753179,75.328351,24.054947)" style="fill:#89969f;fill-opacity:1">
|
||||
<defs id="defs17-6-7-3-62">
|
||||
<path id="path27" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</defs>
|
||||
<clipPath id="clipPath6-6-4-4-7">
|
||||
<path id="use6-9-3-9-8" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<rect x="38" y="67" class="st16" width="64" height="16" clip-path="url(#SVGID_32_-2-5-5-6-6)" id="rect17-3-0-2-5" style="fill:#89969f;fill-opacity:1"/>
|
||||
</g>
|
||||
<g id="g18-7-4-4-6-7" transform="matrix(0.43241056,0,0,0.42753179,75.381505,27.373717)" style="fill:#89969f;fill-opacity:1">
|
||||
<defs id="defs17-6-7-3-6-4">
|
||||
<path id="path28" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</defs>
|
||||
<clipPath id="clipPath6-6-4-4-9-8">
|
||||
<path id="use6-9-3-9-5-5" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<rect x="38" y="67" class="st16" width="64" height="16" clip-path="url(#SVGID_32_-2-5-5-6-8-1)" id="rect17-3-0-2-0-9" style="fill:#89969f;fill-opacity:1"/>
|
||||
</g>
|
||||
<rect style="fill:#b8c5d0;fill-opacity:1;stroke-width:0.456628" id="rect20-1-3" width="0.7906962" height="6.5774407" x="87.603996" y="54.116837"/>
|
||||
<rect style="fill:#b8c5d0;fill-opacity:1;stroke-width:1.11865" id="rect21-86" width="3.4997687" height="0.82786864" x="84.614563" y="39.164116"/>
|
||||
<rect style="fill:#b8c5d0;fill-opacity:1;stroke-width:1.11865" id="rect21-8-04" width="3.4997687" height="0.82786864" x="84.701416" y="43.019638"/>
|
||||
<rect style="fill:#b8c5d0;fill-opacity:1;stroke-width:1.11865" id="rect21-8-3-8" width="3.4997687" height="0.82786864" x="88.380447" y="56.688309"/>
|
||||
<rect style="fill:#b8c5d0;fill-opacity:1;stroke-width:1.11865" id="rect21-8-3-6-8" width="3.4997687" height="0.82786864" x="88.364105" y="59.910507"/>
|
||||
<rect style="fill:#b8c5d0;fill-opacity:1;stroke-width:1.11865" id="rect21-8-0-8" width="3.4997687" height="0.82786864" x="84.715302" y="54.11264"/>
|
||||
<g id="g18-7-0-5" transform="matrix(0.43241056,0,0,0.42753179,134.58749,7.9046882)" style="fill:#89969f;fill-opacity:1">
|
||||
<defs id="defs17-6-3-0">
|
||||
<path id="path31" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</defs>
|
||||
<clipPath id="clipPath6-6-44-4">
|
||||
<path id="use6-9-4-6" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<rect x="38" y="67" class="st16" width="64" height="16" clip-path="url(#SVGID_32_-2-5-4-8)" id="rect17-3-4-2" style="fill:#89969f;fill-opacity:1"/>
|
||||
</g>
|
||||
<g id="g18-7-4-7-5" transform="matrix(0.43241056,0,0,0.42753179,134.59861,11.682031)" style="fill:#89969f;fill-opacity:1">
|
||||
<defs id="defs17-6-7-6-8">
|
||||
<path id="path32" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</defs>
|
||||
<clipPath id="clipPath6-6-4-1-2">
|
||||
<path id="use6-9-3-7-8" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<rect x="38" y="67" class="st16" width="64" height="16" clip-path="url(#SVGID_32_-2-5-5-5-2)" id="rect17-3-0-5-4" style="fill:#89969f;fill-opacity:1"/>
|
||||
</g>
|
||||
<g id="g18-7-4-4-9-7" transform="matrix(0.43241056,0,0,0.42753179,138.28875,25.290974)" style="fill:#89969f;fill-opacity:1">
|
||||
<defs id="defs17-6-7-3-62-2">
|
||||
<path id="path33" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</defs>
|
||||
<clipPath id="clipPath6-6-4-4-7-0">
|
||||
<path id="use6-9-3-9-8-6" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<rect x="38" y="67" class="st16" width="64" height="16" clip-path="url(#SVGID_32_-2-5-5-6-6-0)" id="rect17-3-0-2-5-2" style="fill:#89969f;fill-opacity:1"/>
|
||||
</g>
|
||||
<g id="g18-7-4-4-6-7-9" transform="matrix(0.43241056,0,0,0.42753179,138.34191,28.609744)" style="fill:#89969f;fill-opacity:1">
|
||||
<defs id="defs17-6-7-3-6-4-9">
|
||||
<path id="path34" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</defs>
|
||||
<clipPath id="clipPath6-6-4-4-9-8-8">
|
||||
<path id="use6-9-3-9-5-5-1" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<rect x="38" y="67" class="st16" width="64" height="16" clip-path="url(#SVGID_32_-2-5-5-6-8-1-1)" id="rect17-3-0-2-0-9-3" style="fill:#89969f;fill-opacity:1"/>
|
||||
</g>
|
||||
<rect style="fill:#b8c5d0;fill-opacity:1;stroke-width:0.456628" id="rect20-1-3-1" width="0.7906962" height="6.5774407" x="150.56439" y="55.352852"/>
|
||||
<rect style="fill:#b8c5d0;fill-opacity:1;stroke-width:1.11865" id="rect21-86-0" width="3.4997687" height="0.82786864" x="147.57497" y="40.400116"/>
|
||||
<g id="g18-7-0-5-3" transform="matrix(0.43241056,0,0,0.42753179,134.68389,15.602702)" style="fill:#7da790;fill-opacity:1">
|
||||
<defs id="defs17-6-3-0-8">
|
||||
<path id="path35" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</defs>
|
||||
<clipPath id="clipPath6-6-44-4-5">
|
||||
<path id="use6-9-4-6-6" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<rect x="38" y="67" class="st16" width="64" height="16" clip-path="url(#SVGID_32_-2-5-4-8-9)" id="rect17-3-4-2-6" style="fill:#7da790;fill-opacity:1"/>
|
||||
</g>
|
||||
<rect style="fill:#a8bbb1;fill-opacity:1;stroke-width:1.11865" id="rect21-86-0-4" width="3.4997687" height="0.82786864" x="147.67137" y="48.098137"/>
|
||||
<g id="g18-7-0-5-3-7" transform="matrix(0.43241056,0,0,0.42753179,134.9067,19.629677)" style="fill:#7da790;fill-opacity:1">
|
||||
<defs id="defs17-6-3-0-8-5">
|
||||
<path id="path36" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</defs>
|
||||
<clipPath id="clipPath6-6-44-4-5-9">
|
||||
<path id="use6-9-4-6-6-8" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<rect x="38" y="67" class="st16" width="64" height="16" clip-path="url(#SVGID_32_-2-5-4-8-9-4)" id="rect17-3-4-2-6-7" style="fill:#7da790;fill-opacity:1"/>
|
||||
</g>
|
||||
<rect style="fill:#a8bbb1;fill-opacity:1;stroke-width:1.11865" id="rect21-86-0-4-2" width="3.4997687" height="0.82786864" x="147.89417" y="52.125137"/>
|
||||
<rect style="fill:#b8c5d0;fill-opacity:1;stroke-width:1.11865" id="rect21-8-04-3" width="3.4997687" height="0.82786864" x="147.66182" y="44.255653"/>
|
||||
<rect style="fill:#b8c5d0;fill-opacity:1;stroke-width:1.11865" id="rect21-8-3-8-4" width="3.4997687" height="0.82786864" x="151.34085" y="57.924316"/>
|
||||
<rect style="fill:#b8c5d0;fill-opacity:1;stroke-width:1.11865" id="rect21-8-3-6-8-0" width="3.4997687" height="0.82786864" x="151.32451" y="61.146523"/>
|
||||
<rect style="fill:#b8c5d0;fill-opacity:1;stroke-width:1.11865" id="rect21-8-0-8-3" width="3.4997687" height="0.82786864" x="147.6757" y="55.348663"/>
|
||||
<g id="g18-7-0-5-0" transform="matrix(0.43241056,0,0,0.42753179,4.0752812,5.6170402)" style="fill:#89969f;fill-opacity:1">
|
||||
<defs id="defs17-6-3-0-6">
|
||||
<path id="path19" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</defs>
|
||||
<clipPath id="clipPath6-6-44-4-6">
|
||||
<path id="use6-9-4-6-1" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<rect x="38" y="67" class="st16" width="64" height="16" clip-path="url(#SVGID_32_-2-5-4-8-7)" id="rect17-3-4-2-8" style="fill:#89969f;fill-opacity:1"/>
|
||||
</g>
|
||||
<g id="g18-7-4-7-5-7" transform="matrix(0.43241056,0,0,0.42753179,4.0863965,9.3943842)" style="fill:#89969f;fill-opacity:1">
|
||||
<defs id="defs17-6-7-6-8-9">
|
||||
<path id="path20" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</defs>
|
||||
<clipPath id="clipPath6-6-4-1-2-0">
|
||||
<path id="use6-9-3-7-8-2" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<rect x="38" y="67" class="st16" width="64" height="16" clip-path="url(#SVGID_32_-2-5-5-5-2-3)" id="rect17-3-0-5-4-3" style="fill:#89969f;fill-opacity:1"/>
|
||||
</g>
|
||||
<g id="g18-7-4-4-9-7-7" transform="matrix(0.43241056,0,0,0.42753179,7.7765425,23.003326)" style="fill:#89969f;fill-opacity:1">
|
||||
<defs id="defs17-6-7-3-62-2-5">
|
||||
<path id="path29" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</defs>
|
||||
<clipPath id="clipPath6-6-4-4-7-0-2">
|
||||
<path id="use6-9-3-9-8-6-2" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<rect x="38" y="67" class="st16" width="64" height="16" clip-path="url(#SVGID_32_-2-5-5-6-6-0-6)" id="rect17-3-0-2-5-2-8" style="fill:#89969f;fill-opacity:1"/>
|
||||
</g>
|
||||
<g id="g18-7-4-4-6-7-9-9" transform="matrix(0.43241056,0,0,0.42753179,7.8296965,26.322097)" style="fill:#89969f;fill-opacity:1">
|
||||
<defs id="defs17-6-7-3-6-4-9-7">
|
||||
<path id="path30" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</defs>
|
||||
<clipPath id="clipPath6-6-4-4-9-8-8-6">
|
||||
<path id="use6-9-3-9-5-5-1-1" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<rect x="38" y="67" class="st16" width="64" height="16" clip-path="url(#SVGID_32_-2-5-5-6-8-1-1-9)" id="rect17-3-0-2-0-9-3-2" style="fill:#89969f;fill-opacity:1"/>
|
||||
</g>
|
||||
<rect style="fill:#b8c5d0;fill-opacity:1;stroke-width:0.456628" id="rect20-1-3-1-3" width="0.7906962" height="6.5774407" x="20.052189" y="53.065201"/>
|
||||
<rect style="fill:#b8c5d0;fill-opacity:1;stroke-width:1.11865" id="rect21-86-0-1" width="3.4997687" height="0.82786864" x="17.062759" y="38.11248"/>
|
||||
<g id="g18-7-0-5-3-9" transform="matrix(0.43241056,0,0,0.42753179,4.1716787,13.315055)" style="fill:#7da790;fill-opacity:1">
|
||||
<defs id="defs17-6-3-0-8-4">
|
||||
<path id="path37" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</defs>
|
||||
<clipPath id="clipPath6-6-44-4-5-8">
|
||||
<path id="use6-9-4-6-6-4" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<rect x="38" y="67" class="st16" width="64" height="16" clip-path="url(#SVGID_32_-2-5-4-8-9-2)" id="rect17-3-4-2-6-5" style="fill:#7da790;fill-opacity:1"/>
|
||||
</g>
|
||||
<rect style="fill:#a8bbb1;fill-opacity:1;stroke-width:1.11865" id="rect21-86-0-4-0" width="3.4997687" height="0.82786864" x="17.159159" y="45.810486"/>
|
||||
<g id="g18-7-0-5-3-7-3" transform="matrix(0.43241056,0,0,0.42753179,4.3944879,17.34203)" style="fill:#7da790;fill-opacity:1">
|
||||
<defs id="defs17-6-3-0-8-5-6">
|
||||
<path id="path38" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</defs>
|
||||
<clipPath id="clipPath6-6-44-4-5-9-0">
|
||||
<path id="use6-9-4-6-6-8-6" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<rect x="38" y="67" class="st16" width="64" height="16" clip-path="url(#SVGID_32_-2-5-4-8-9-4-0)" id="rect17-3-4-2-6-7-3" style="fill:#7da790;fill-opacity:1"/>
|
||||
</g>
|
||||
<rect style="fill:#a8bbb1;fill-opacity:1;stroke-width:1.11865" id="rect21-86-0-4-2-2" width="3.4997687" height="0.82786864" x="17.381956" y="49.837486"/>
|
||||
<g id="g18-7-0-5-3-9-7" transform="matrix(0.43241056,0,0,0.42753179,3.9533595,31.786743)" style="fill:#a68292;fill-opacity:1">
|
||||
<defs id="defs17-6-3-0-8-4-4">
|
||||
<path id="path39" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</defs>
|
||||
<clipPath id="clipPath6-6-44-4-5-8-2">
|
||||
<path id="use6-9-4-6-6-4-5" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<rect x="38" y="67" class="st16" width="64" height="16" clip-path="url(#SVGID_32_-2-5-4-8-9-2-7)" id="rect17-3-4-2-6-5-4" style="fill:#a68292;fill-opacity:1"/>
|
||||
</g>
|
||||
<rect style="fill:#d4c2ca;fill-opacity:1;stroke-width:1.11865" id="rect21-86-0-4-0-7" width="3.4997687" height="0.82786864" x="16.940838" y="64.282166"/>
|
||||
<g id="g18-7-0-5-3-7-3-4" transform="matrix(0.43241056,0,0,0.42753179,4.1761688,35.813721)" style="fill:#a68292;fill-opacity:1">
|
||||
<defs id="defs17-6-3-0-8-5-6-4">
|
||||
<path id="path40" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</defs>
|
||||
<clipPath id="clipPath6-6-44-4-5-9-0-0">
|
||||
<path id="use6-9-4-6-6-8-6-7" d="m 44,72 h 52 c 0.55,0 1,0.45 1,1 v 4 c 0,0.55 -0.45,1 -1,1 H 44 c -0.55,0 -1,-0.45 -1,-1 v -4 c 0,-0.55 0.45,-1 1,-1"/>
|
||||
</clipPath>
|
||||
<rect x="38" y="67" class="st16" width="64" height="16" clip-path="url(#SVGID_32_-2-5-4-8-9-4-0-5)" id="rect17-3-4-2-6-7-3-8" style="fill:#a68292;fill-opacity:1"/>
|
||||
</g>
|
||||
<rect style="fill:#d4c2ca;fill-opacity:1;stroke-width:1.11865" id="rect21-86-0-4-2-2-6" width="3.4997687" height="0.82786864" x="17.163635" y="68.309174"/>
|
||||
<rect style="fill:#b8c5d0;fill-opacity:1;stroke-width:1.11865" id="rect21-8-04-3-0" width="3.4997687" height="0.82786864" x="17.149611" y="41.968002"/>
|
||||
<rect style="fill:#b8c5d0;fill-opacity:1;stroke-width:1.11865" id="rect21-8-3-8-4-6" width="3.4997687" height="0.82786864" x="20.828642" y="55.636681"/>
|
||||
<rect style="fill:#b8c5d0;fill-opacity:1;stroke-width:1.11865" id="rect21-8-3-6-8-0-1" width="3.4997687" height="0.82786864" x="20.812304" y="58.858902"/>
|
||||
<rect style="fill:#b8c5d0;fill-opacity:1;stroke-width:1.11865" id="rect21-8-0-8-3-5" width="3.4997687" height="0.82786864" x="17.163498" y="53.060997"/>
|
||||
<text xml:space="preserve" style="font-size:13.4238px;fill:#89969f;fill-opacity:1;stroke-width:1.11865" x="81.859032" y="92.687805" id="text31"><tspan sodipodi:role="line" id="tspan31" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.45766px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#89969f;fill-opacity:1;stroke-width:1.11865" x="81.859032" y="92.687805">Read Write</tspan></text>
|
||||
<text xml:space="preserve" style="font-size:13.4238px;fill:#89969f;fill-opacity:1;stroke-width:1.11865" x="25.950493" y="92.955856" id="text31-1"><tspan sodipodi:role="line" id="tspan31-4" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.45766px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#89969f;fill-opacity:1;stroke-width:1.11865" x="25.950493" y="92.955856">Structure</tspan></text>
|
||||
<text xml:space="preserve" style="font-size:13.4238px;fill:#31473b;fill-opacity:0.533333;stroke-width:1.11865" x="49.067989" y="49.023651" id="text31-1-8"><tspan sodipodi:role="line" id="tspan31-4-9" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.96612px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#175131;fill-opacity:0.533333;stroke-width:1.11865" x="49.067989" y="49.023651">hidden</tspan></text>
|
||||
<text xml:space="preserve" style="font-size:13.4238px;fill:#953861;fill-opacity:1;stroke-width:1.11865" x="49.006676" y="69.346802" id="text31-1-8-0"><tspan sodipodi:role="line" id="tspan31-4-9-6" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.96612px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#953861;fill-opacity:1;stroke-width:1.11865" x="49.006676" y="69.346802">disabled</tspan></text>
|
||||
<text xml:space="preserve" style="font-size:13.4238px;fill:#89969f;fill-opacity:1;stroke-width:1.11865" x="141.6644" y="92.853027" id="text31-8"><tspan sodipodi:role="line" id="tspan31-9" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.45766px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#89969f;fill-opacity:1;stroke-width:1.11865" x="141.6644" y="92.853027">Read Only</tspan></text>
|
||||
<rect style="fill:#b8c5d0;fill-opacity:1;stroke-width:1.19498" id="rect20-3-1-9" width="0.94683659" height="37.616936" x="16.526701" y="35.147079"/>
|
||||
<rect style="fill:#b8c5d0;fill-opacity:1;stroke-width:1.19498" id="rect20-3-1-9-0" width="0.94683659" height="37.616936" x="84.226616" y="35.729088"/>
|
||||
<rect style="fill:#b8c5d0;fill-opacity:1;stroke-width:1.19498" id="rect20-3-1-9-0-1" width="0.94683659" height="37.616936" x="146.87093" y="36.847733"/>
|
||||
<rect style="fill:none;fill-opacity:0.533333;stroke:none;stroke-width:0.264583" id="rect40" width="193.10428" height="95.232437" x="7.0377231" y="10.610595"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 38 KiB |
BIN
docs/images/read_write.png
Normal file
|
After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 49 KiB |
BIN
docs/images/tiramisu_get_set.png
Normal file
|
After Width: | Height: | Size: 88 KiB |
|
|
@ -8,56 +8,77 @@
|
|||
Rougail
|
||||
===========
|
||||
|
||||
.. todo:: définir les termes suivants:
|
||||
|
||||
4 family.rst:25: WARNING: label non défini: 'convention on variable names'
|
||||
5 structureddata.rst:89: WARNING: term not in glossary: 'variable_namespace'
|
||||
9 variable.rst:38: WARNING: label non défini: 'convention on variable names'
|
||||
11 variable.rst:154: WARNING: term not in glossary: 'required'
|
||||
|
||||
|
||||
.. todo:: créer les documents suivants:
|
||||
|
||||
1 rougail/docs/family.rst:102: WARNING: unknown document: 'tutorial/mode'
|
||||
3 rougail/docs/structureddata.rst:89: WARNING: term not in glossary: 'variable_namespace'
|
||||
4 rougail/docs/variable.rst:163: WARNING: unknown document: 'tutorial/mode'
|
||||
5 rougail/docs/variable.rst:235: WARNING: unknown document: 'tutorial/validators'
|
||||
6 rougail/docs/variable.rst:263: WARNING: unknown document: 'tutorial/autosave'
|
||||
|
||||
.. image:: images/logo.png
|
||||
|
||||
- is a `delicious cooked dish <https://fr.wikipedia.org/wiki/Rougail>`_ from the Mauritius and Reunion Islands,
|
||||
- is a `delicious cooked dish <https://fr.wikipedia.org/wiki/Rougail>`_ from the Mauritius and Reunion Islands,
|
||||
|
||||
- it is also a `Python3 <https://www.python.org/>`_ library which enables us to conveniently load application :term:`variable`\ s in a simple `YAML <https://yaml.org/>`_ format in such a way that the end user consumer can handle them consistently (that is, against an user-defined consistency).
|
||||
|
||||
In other words, using Rougail in your application or your python libraries can tansform end user consumer defined consistency rules into highly consistent business objects.
|
||||
|
||||
We then have to say that the handling system used to ensure the variables integrity is another python library, called :term:`Tiramisu`. Rougail is currently strongly affiliated with Tiramisu.
|
||||
|
||||
.. note:: Rougail is currently intended to work in coordination with :term:`Tiramisu` and **is not** intended to be connected with any other consistency handling system.
|
||||
|
||||
Explained differently, Rougail allows you to easily implement an integration of the powerful tiramisu consistency handling system.
|
||||
- it is also a tool which enables us to conveniently load :term:`variable`\ s in `YAML <https://yaml.org/>`_ file format in such a way that the end user consumer can handle them consistently (that is, against an user-defined consistency).
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
:caption: Getting started
|
||||
:caption: What is it all about
|
||||
|
||||
gettingstarted
|
||||
tutorial
|
||||
abstract
|
||||
vac
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
:caption: The library
|
||||
:caption: Structured data
|
||||
|
||||
structured_data/index
|
||||
format_content/index
|
||||
tutorial/index
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
:caption: User data
|
||||
|
||||
user_data/prerequisites
|
||||
user_data/index
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
:caption: Output
|
||||
|
||||
output/index
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
:caption: The library and the tools
|
||||
|
||||
library
|
||||
configuration
|
||||
cli
|
||||
library/index
|
||||
tiramisu
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
:caption: The dictionaries
|
||||
|
||||
dictionary
|
||||
dict_convention
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
:caption: The variables
|
||||
|
||||
variable
|
||||
family
|
||||
fill
|
||||
Value checks <check>
|
||||
condition
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
:caption: Notes
|
||||
:caption: Developper notes
|
||||
|
||||
release
|
||||
developer
|
||||
documentation
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
install
|
||||
|
||||
.. rubric:: Index page
|
||||
|
||||
|
|
|
|||
35
docs/install.rst
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
.. _installation:
|
||||
|
||||
Rougail library installation
|
||||
======================================
|
||||
|
||||
Activate you virtual environment
|
||||
------------------------------------
|
||||
|
||||
- Open a shell session
|
||||
|
||||
- install the virtual environment: `python -m'venv' .venv`
|
||||
- activate it `./.venv/bin/activate` (or `.venv\Scripts\activate.exe` under windows)
|
||||
|
||||
Standard installation
|
||||
---------------------------
|
||||
|
||||
You can use the `pip` python installer, here is the install command:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip install rougail
|
||||
|
||||
Installation of third-party libraries
|
||||
-------------------------------------------
|
||||
|
||||
First, download the :download:`requirements.txt file: <install/requirements.txt>`
|
||||
|
||||
.. literalinclude:: install/requirements.txt
|
||||
:caption: The :file:`requirements.txt` requirements file
|
||||
|
||||
Then in your virtual environment, recursively install the third-party libraries as follows:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip install -r requirements.txt --extra-index-url https://test.pypi.org/simple/
|
||||
16
docs/install/requirements.txt
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
rougail==1.2.0rc3
|
||||
rougail-cli==1.0.0rc0
|
||||
rougail-output-ansible==1.0.0rc0
|
||||
rougail-output-display==1.0.0rc0
|
||||
rougail-output-doc==1.0.0rc0
|
||||
rougail-output-formatter==1.0.0rc0
|
||||
rougail-output-json==1.0.0rc0
|
||||
rougail-output-table==0.1.0rc0
|
||||
rougail-user-data-ansible==1.0.0rc0
|
||||
rougail-user-data-bitwarden==1.0.0rc1
|
||||
rougail-user-data-commandline==1.0.0rc2
|
||||
rougail-user-data-environment==1.0.0rc0
|
||||
rougail-user-data-questionary==1.0.0rc0
|
||||
rougail-user-data-yaml==1.0.0rc1
|
||||
tiramisu==5.2.0rc0
|
||||
tiramisu-cmdline-parser==1.0.0rc0
|
||||
233
docs/library.rst
|
|
@ -1,233 +0,0 @@
|
|||
`Rougail`'s library description
|
||||
=================================
|
||||
|
||||
Rougail is a configuration management library that allows you to load variables in a simple and convenient way.
|
||||
|
||||
In the following examples, we will use a specific configuration of Rougail.
|
||||
You will find all the configuraiton options in :doc:`configuration`.
|
||||
|
||||
To load the configuration you must import the `RougailConfig` class and set the `dictionaries_dir` values:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from rougail import RougailConfig
|
||||
|
||||
RougailConfig['dictionaries_dir'] = ['dict']
|
||||
|
||||
Let's convert a dictionary
|
||||
-----------------------------
|
||||
|
||||
As a reminder, a :term:`dictionary` is a set of instructions that will allow us to create :term:`families` and :term:`variables`.
|
||||
|
||||
Let's start by creating a simple dictionary.
|
||||
|
||||
Here is a first :file:`dict/00-base.yml` dictionary:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
my_variable:
|
||||
default: my_value
|
||||
|
||||
Then, let's create the :term:`Tiramisu` objects via the following script:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the `script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
|
||||
RougailConfig['dictionaries_dir'] = ['dict']
|
||||
rougail = Rougail()
|
||||
config = rougail.get_config()
|
||||
print(config.value.get())
|
||||
|
||||
Let's execute `script.py`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python3 script.py
|
||||
{'rougail.my_variable': 'my_value'}
|
||||
|
||||
Let's convert an extra dictionary
|
||||
-------------------------------------
|
||||
|
||||
.. index:: extras
|
||||
|
||||
The default namespace for variables and families is `rougail`. It is possible to define other namespaces. These additional namespaces are called `extras`.
|
||||
|
||||
.. FIXME: faire une page pour les extras
|
||||
|
||||
Additional namespaces are defined during configuration.
|
||||
|
||||
For example, here's how to add an `example` namespace:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
RougailConfig['extra_dictionaries']['example'] = ['extras/']
|
||||
|
||||
Then let's create an extra :term:`dictionary` :file:`extras/00-base.yml`:
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: the :file:`extras/00-base.yml` file content
|
||||
---
|
||||
version: '1.1'
|
||||
my_variable_extra:
|
||||
default: my_value_extra
|
||||
|
||||
Then, let's create the :term:`Tiramisu` objects via the following :file:`script.py` script:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
|
||||
RougailConfig['dictionaries_dir'] = ['dict']
|
||||
RougailConfig['extra_dictionaries']['example'] = ['extras/']
|
||||
rougail = Rougail()
|
||||
config = rougail.get_config()
|
||||
print(config.value.dict())
|
||||
|
||||
Let's execute `script.py`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python3 script.py
|
||||
{'rougail.my_variable': 'my_value', 'example.my_variable_extra': 'my_value_extra'}
|
||||
|
||||
Let's create a custom function
|
||||
----------------------------------
|
||||
|
||||
We create the complementary :term:`dictionary` named :file:`dict/01-function.yml` so that the `my_variable_jinja` variable is :term:`calculated`:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
my_variable_jinja:
|
||||
type: "string"
|
||||
default:
|
||||
type: jinja
|
||||
jinja: "{{ return_no() }}"
|
||||
|
||||
Then let's define the :func:`return_no` function in :file:`functions.py`:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`functions.py` content
|
||||
|
||||
def return_no():
|
||||
return 'no'
|
||||
|
||||
Then, let's create the :term:`Tiramisu` objects via the following script:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the `script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
|
||||
RougailConfig['dictionaries_dir'] = ['dict']
|
||||
RougailConfig['extra_dictionaries']['example'] = ['extras/']
|
||||
RougailConfig['functions_file'] = 'functions.py'
|
||||
rougail = Rougail()
|
||||
config = rougail.get_config()
|
||||
print(config.value.dict())
|
||||
|
||||
Let's execute `script.py`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python3 script.py
|
||||
{'rougail.my_variable': 'my_value', 'rougail.my_variable_jinja': 'no', 'example.my_variable_extra': 'my_value_extra'}
|
||||
|
||||
The value of the `my_variable_extra` variable is calculated, and it's value comes from the :func:`return_no` function.
|
||||
|
||||
Create your own type
|
||||
----------------------
|
||||
|
||||
A variable has a type. This type enables the variable to define the values that are accepted by this variable.
|
||||
|
||||
There is a series of default types, but obviously not all cases are taken.
|
||||
|
||||
It's possible to create your own type.
|
||||
|
||||
Here an example to a lipogram option (in a string, we cannot use "e" character):
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the `lipogram.py` file content
|
||||
|
||||
from tiramisu import StrOption
|
||||
class LipogramOption(StrOption):
|
||||
__slots__ = tuple()
|
||||
_type = 'lipogram'
|
||||
|
||||
def validate(self,
|
||||
value):
|
||||
super().validate(value)
|
||||
# verify that there is any 'e' in the sentense
|
||||
if 'e' in value:
|
||||
raise ValueError('Perec wrote a book without any "e", you could not do it in a simple sentence?')
|
||||
|
||||
To add the new lipogram type in Rougail:
|
||||
|
||||
.. code-block:: python
|
||||
>>> from rougail import Rougail, RougailConfig
|
||||
>>> RougailConfig['dictionaries_dir'] = ['dict']
|
||||
>>> RougailConfig['custom_types']['lipogram'] = LipogramOption
|
||||
|
||||
Now, we can use lipogram type.
|
||||
Here is a :file:`dict/00-base.yml` dictionary:
|
||||
|
||||
.. code-block:: yaml
|
||||
---
|
||||
version: '1.1'
|
||||
var:
|
||||
type: lipogram
|
||||
|
||||
.. code-block:: python
|
||||
>>> rougail = Rougail()
|
||||
>>> config = rougail.get_config()
|
||||
>>> config.option('rougail.var').value.set('blah')
|
||||
>>> config.option('rougail.var').value.set('I just want to add a quality string that has no bad characters')
|
||||
[...]
|
||||
tiramisu.error.ValueOptionError: "I just want to add a quality string that has no bad characters" is an invalid lipogram for "var", Perec wrote a book without any "e", you could not do it in a simple sentence?
|
||||
|
||||
Upgrade dictionnaries to upper version
|
||||
----------------------------------------
|
||||
|
||||
All dictionnaries has a format version number.
|
||||
When a new format version is proposed, it is possible to automatically convert the files to the new version.
|
||||
|
||||
We create a term:`dictionary` named :file:`dict/01-upgrade.yml` with version 1.0:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
my_variable:
|
||||
multi: true
|
||||
my_dyn_family:
|
||||
type: "dynamic"
|
||||
variable: my_variable
|
||||
a_variable:
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
>>> from rougail import RougailUpgrade, RougailConfig
|
||||
>>> RougailConfig['dictionaries_dir'] = ['dict']
|
||||
>>> upgrade = RougailUpgrade()
|
||||
>>> upgrade.load_dictionaries('dict_converted')
|
||||
|
||||
The term:`dictionary` named :file:`dict_converted/01-upgrade.yml` is in version 1.1:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
version: '1.1'
|
||||
my_variable:
|
||||
multi: true
|
||||
my_dyn_family:
|
||||
type: dynamic
|
||||
a_variable: null
|
||||
dynamic:
|
||||
type: variable
|
||||
variable: my_variable
|
||||
propertyerror: false
|
||||
47
docs/library/custom_function.rst
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
Let's create a custom function
|
||||
==============================
|
||||
|
||||
We create the complementary :term:`structure file` named :file:`dict/01-function.yml` so that the `my_variable_jinja` variable is :term:`calculated`:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable_jinja:
|
||||
default:
|
||||
type: jinja
|
||||
jinja: "{{ return_no() }}"
|
||||
...
|
||||
|
||||
Then let's define the :func:`return_no` function in :file:`functions.py`:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`functions.py` content
|
||||
|
||||
def return_no():
|
||||
return 'no'
|
||||
|
||||
Then, let's create the :term:`Tiramisu` objects via the following script:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the `script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
|
||||
RougailConfig['main_structural_directories'] = ['dict']
|
||||
RougailConfig['extra_namespaces']['example'] = ['extras/']
|
||||
RougailConfig['functions_file'] = 'functions.py'
|
||||
rougail = Rougail()
|
||||
config = rougail.get_config()
|
||||
print(config.value.dict())
|
||||
|
||||
Let's execute `script.py`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python3 script.py
|
||||
{'rougail.my_variable': 'my_value', 'rougail.my_variable_jinja': 'no', 'example.my_variable_extra': 'my_value_extra'}
|
||||
|
||||
The value of the `my_variable_extra` variable is calculated, and it's value comes from the :func:`return_no` function.
|
||||
45
docs/library/extra.rst
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
Let's convert an extra namespace structural file
|
||||
================================================
|
||||
|
||||
.. index:: extras
|
||||
|
||||
The default namespace for variables and families is `rougail`. It is possible to define other namespaces. These additional namespaces are called `extras`.
|
||||
|
||||
.. FIXME: faire une page pour les extras
|
||||
|
||||
Additional namespaces are defined during configuration.
|
||||
|
||||
For example, here's how to add an `example` namespace:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
RougailConfig['extra_namespaces']['example'] = ['extras/']
|
||||
|
||||
Then let's create an extra :term:`structure file` :file:`extras/00-base.yml`:
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: the :file:`extras/00-base.yml` file content
|
||||
---
|
||||
version: '1.1'
|
||||
my_variable_extra:
|
||||
default: my_value_extra
|
||||
|
||||
Then, let's create the :term:`Tiramisu` objects via the following :file:`script.py` script:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
|
||||
RougailConfig['main_structural_directories'] = ['dict/']
|
||||
RougailConfig['extra_namespaces']['example'] = ['extras/']
|
||||
rougail = Rougail()
|
||||
config = rougail.get_config()
|
||||
print(config.value.dict())
|
||||
|
||||
Let's execute `script.py`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python3 script.py
|
||||
{'rougail.my_variable': 'my_value', 'example.my_variable_extra': 'my_value_extra'}
|
||||
87
docs/library/index.rst
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
`Rougail`'s library description
|
||||
=================================
|
||||
|
||||
Rougail is a configuration management library that allows you to load variables in a simple and convenient way.
|
||||
|
||||
In the following examples, we will use a specific configuration of Rougail.
|
||||
|
||||
|
||||
.. FIXME: You will find all the configuration options in doc:`configuration`
|
||||
find a document with all the configuration options
|
||||
|
||||
To load the configuration you must import the `RougailConfig` class and set the `main_structural_directories` values:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from rougail import RougailConfig
|
||||
|
||||
RougailConfig['main_structural_directories'] = ['dict']
|
||||
|
||||
Let's convert a our first structural file
|
||||
-----------------------------------------
|
||||
|
||||
As a reminder, a :term:`structure file` is a set of instructions that will allow us to create :term:`families <family>` and :term:`variables <variable>`.
|
||||
|
||||
Let's start by creating a simple structure file.
|
||||
|
||||
Here is a first :file:`dict/00-base.yml` structure file:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable: my_value # my variable
|
||||
...
|
||||
|
||||
Then, let's create the :term:`Tiramisu` objects via the following script:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the `script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
|
||||
RougailConfig['main_structural_directories'] = ['dict']
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
print(config.value.get())
|
||||
|
||||
.. demo:: Let's execute `script.py`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python3 script.py
|
||||
{'rougail.my_variable': 'my_value'}
|
||||
|
||||
The operator role
|
||||
--------------------
|
||||
|
||||
The :term:`operator` role corresponds to the :term:`tiramisu` settings:
|
||||
|
||||
.. image:: ../images/tiramisu_get_set.png
|
||||
|
||||
.. index:: questionary
|
||||
|
||||
But instead of coding in the end user developer way, the opterator will prefer using the Rougail CLI interface:
|
||||
|
||||
.. image:: ../images/QuestionaryChoice.png
|
||||
|
||||
|
||||
The Rougail CLI can output a rather complete view of the dataet:
|
||||
|
||||
.. image:: ../images/UserDataOutput.png
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
:caption: Use library
|
||||
|
||||
user_data
|
||||
output
|
||||
parse
|
||||
tags
|
||||
rougailconfig_load_from_cli
|
||||
extra
|
||||
custom_function
|
||||
own_type
|
||||
upgrade
|
||||
269
docs/library/output.rst
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
Display the result
|
||||
==================
|
||||
|
||||
After construct a configuration, loads user data, you can choose this configuration in different output format.
|
||||
|
||||
First of create, let's create a structural file like this:
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: the :file:`dist/00-base.yml` file content
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable: my value # My first variable
|
||||
|
||||
my_boolean_variable: true # My boolean variable
|
||||
|
||||
my_integer_variable: 1 # My integer variable
|
||||
|
||||
my_secret_variable:
|
||||
description: My secret variable
|
||||
type: secret
|
||||
default: MyVeryStrongPassword
|
||||
...
|
||||
|
||||
Display in a console
|
||||
--------------------
|
||||
|
||||
We can display configuration directly in the console:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
from rougail.output_console import RougailOutputConsole
|
||||
|
||||
RougailConfig["main_namespace"] = None
|
||||
RougailConfig["main_structural_directories"] = ["dist/"]
|
||||
RougailConfig["step.output"] = "console"
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
config.property.read_only()
|
||||
RougailOutputConsole(config).print()
|
||||
|
||||
.. FIXME display console!
|
||||
|
||||
console.key_is_description
|
||||
''''''''''''''''''''''''''
|
||||
|
||||
By default, the key is the variable description, if you prefer have only the path:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
from rougail.output_json import RougailOutputJson
|
||||
|
||||
RougailConfig["main_namespace"] = None
|
||||
RougailConfig["main_structural_directories"] = ["dist/"]
|
||||
RougailConfig["step.output"] = "console"
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
config.property.read_only()
|
||||
RougailOutputJson(config).print()
|
||||
|
||||
|
||||
.. FIXME display console!
|
||||
|
||||
console.show_secrets
|
||||
''''''''''''''''''''
|
||||
|
||||
Secrets are remplace by "*******", to display real secrets:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
from rougail.output_console import RougailOutputConsole
|
||||
|
||||
RougailConfig["main_namespace"] = None
|
||||
RougailConfig["main_structural_directories"] = ["dist/"]
|
||||
RougailConfig["step.output"] = "console"
|
||||
RougailConfig["console.show_secrets"] = True
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
config.property.read_only()
|
||||
RougailOutputConsole(config).print()
|
||||
|
||||
.. FIXME display console!
|
||||
|
||||
console.mandatory
|
||||
'''''''''''''''''
|
||||
|
||||
Before display configuration, mandatories variables are check. If you don't want, add the parameter `console.mandatory` to False:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
from rougail.output_console import RougailOutputConsole
|
||||
|
||||
RougailConfig["main_namespace"] = None
|
||||
RougailConfig["main_structural_directories"] = ["dist/"]
|
||||
RougailConfig["step.output"] = "console"
|
||||
RougailConfig["console.mandatory"] = False
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
config.property.read_only()
|
||||
RougailOutputConsole(config).print()
|
||||
|
||||
.. FIXME display console!
|
||||
|
||||
JSON
|
||||
----
|
||||
|
||||
Your script can return a JSON object:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
from rougail.output_console import RougailOutputConsole
|
||||
|
||||
RougailConfig["main_namespace"] = None
|
||||
RougailConfig["main_structural_directories"] = ["dist/"]
|
||||
RougailConfig["step.output"] = "json"
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
config.property.read_only()
|
||||
RougailOutputConsole(config).print()
|
||||
|
||||
Let's try this script:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python script.py
|
||||
{
|
||||
"my_variable": "my value",
|
||||
"my_boolean_variable": true,
|
||||
"my_integer_variable": 1,
|
||||
"my_secret_variable": "MyVeryStrongPassword"
|
||||
}
|
||||
|
||||
ANSIBLE
|
||||
-------
|
||||
|
||||
It's possible to use Ansible has a output format.
|
||||
|
||||
The goal is here to use Ansible has a dynamic user's inventories structure manage by Rougail.
|
||||
|
||||
This output needs an extra namespace, named, by default, "hosts". This namespace define your hosts and groups.
|
||||
|
||||
Let's create a single group "my_group" with one host "group1.net":
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: the :file:`hosts/00-hosts.yml` file content
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
hostnames:
|
||||
|
||||
my_group:
|
||||
|
||||
hosts:
|
||||
type: domainname
|
||||
default:
|
||||
- group1.net
|
||||
...
|
||||
|
||||
Now we can generate Ansible inventory:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
#!/bin/env python
|
||||
from rougail import Rougail, RougailConfig
|
||||
from rougail.output_ansible import RougailOutputAnsible
|
||||
|
||||
RougailConfig["main_namespace"] = "main"
|
||||
RougailConfig["main_structural_directories"] = ["dist/"]
|
||||
RougailConfig['extra_namespaces']['hosts'] = ['hosts/']
|
||||
RougailConfig["step.output"] = "ansible"
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
config.property.read_only()
|
||||
RougailOutputAnsible(config).print()
|
||||
|
||||
We will retrieved all ours variables associate to this group with all variables inside the namespace `main`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python script.py
|
||||
{
|
||||
"_meta": {
|
||||
"hostvars": {
|
||||
"group1.net": {
|
||||
"ansible_host": "group1.net",
|
||||
"main": {
|
||||
"my_variable": "my value",
|
||||
"my_boolean_variable": true,
|
||||
"my_integer_variable": 1,
|
||||
"my_secret_variable": "MyVeryStrongPassword"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"my_group": {
|
||||
"hosts": [
|
||||
"group1.net"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
We can now use our script as an inventory source in Ansible:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ chmod +x script.py
|
||||
$ ansible-inventory -i script.py --list
|
||||
{
|
||||
"_meta": {
|
||||
"hostvars": {
|
||||
"group1.net": {
|
||||
"ansible_host": "group1.net",
|
||||
"main": {
|
||||
"my_boolean_variable": true,
|
||||
"my_integer_variable": 1,
|
||||
"my_secret_variable": "MyVeryStrongPassword",
|
||||
"my_variable": "my value"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"all": {
|
||||
"children": [
|
||||
"ungrouped",
|
||||
"my_group"
|
||||
]
|
||||
},
|
||||
"my_group": {
|
||||
"hosts": [
|
||||
"group1.net"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
DOC
|
||||
---
|
||||
|
||||
We can generate the documentation of all the Rougail variable:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
from rougail.output_doc import RougailOutputDoc
|
||||
|
||||
RougailConfig["main_namespace"] = "main"
|
||||
RougailConfig["main_structural_directories"] = ["dist/"]
|
||||
RougailConfig["step.output"] = "doc"
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
config.property.read_only()
|
||||
RougailOutputDoc(config).print()
|
||||
|
||||
.. FIXME : display
|
||||
52
docs/library/own_type.rst
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
Create your own type
|
||||
====================
|
||||
|
||||
A variable has a type. This type enables the variable to define the values that are accepted by this variable.
|
||||
|
||||
There is a series of default types, but obviously not all cases are taken.
|
||||
|
||||
It's possible to create your own type.
|
||||
|
||||
Here an example to a lipogram option (in a string, we cannot use "e" character):
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the `lipogram.py` file content
|
||||
|
||||
from tiramisu import StrOption
|
||||
class LipogramOption(StrOption):
|
||||
__slots__ = tuple()
|
||||
_type = 'lipogram'
|
||||
|
||||
def validate(self,
|
||||
value):
|
||||
super().validate(value)
|
||||
# verify that there is any 'e' in the sentense
|
||||
if 'e' in value:
|
||||
raise ValueError('Perec wrote a book without any "e", you could not do it in a simple sentence?')
|
||||
|
||||
To add the new lipogram type in Rougail:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> from rougail import Rougail, RougailConfig
|
||||
>>> RougailConfig['main_structural_directories'] = ['dict']
|
||||
>>> RougailConfig['custom_types']['lipogram'] = LipogramOption
|
||||
|
||||
Now, we can use lipogram type.
|
||||
Here is a :file:`dict/00-base.yml` structure file:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
var:
|
||||
type: lipogram
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> rougail = Rougail()
|
||||
>>> config = rougail.get_config()
|
||||
>>> config.option('rougail.var').value.set('blah')
|
||||
>>> config.option('rougail.var').value.set('I just want to add a quality string that has no bad characters')
|
||||
[...]
|
||||
tiramisu.error.ValueOptionError: "I just want to add a quality string that has no bad characters" is an invalid lipogram for "var", Perec wrote a book without any "e", you could not do it in a simple sentence?
|
||||
260
docs/library/parse.rst
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
Retrieve all variables and families
|
||||
===================================
|
||||
|
||||
Rougail returns a :term:`Tiramisu` config.
|
||||
|
||||
Let's retrieve our variables and families to manager this.
|
||||
|
||||
First of all, create our structural file:
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: the :file:`dist/00-base.yml` file content
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable: # a simple variable
|
||||
- value1
|
||||
- value2
|
||||
|
||||
a_family: # a simple family
|
||||
|
||||
my_variable: my_value # a simple variable inside the family
|
||||
|
||||
a_dyn_family_{{ identifier }}:
|
||||
description: a dynamic family for "{{ identifier }}"
|
||||
dynamic:
|
||||
variable: _.my_variable
|
||||
|
||||
a_leadership:
|
||||
description: a leader family
|
||||
|
||||
a_leader: # a leader variable
|
||||
a_follower: # a follower variable
|
||||
...
|
||||
|
||||
Walk through our config
|
||||
-------------------------
|
||||
|
||||
Create our first script to walk through our config:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
|
||||
RougailConfig['main_structural_directories'] = ["dist/"]
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
|
||||
def walk(config):
|
||||
for option in config:
|
||||
print(option.description())
|
||||
if option.isoptiondescription():
|
||||
walk(option)
|
||||
|
||||
if __name__ == '__main__':
|
||||
walk(config)
|
||||
|
||||
Let's execute `script.py`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python3 script.py
|
||||
rougail
|
||||
rougail.my_variable (a simple variable)
|
||||
rougail.a_family (a simple family)
|
||||
rougail.a_family.my_variable (a simple variable inside the family)
|
||||
rougail.a_dyn_family_value1 (a dynamic family for "value1")
|
||||
rougail.a_dyn_family_value1.a_leadership (a leader family)
|
||||
rougail.a_dyn_family_value1.a_leadership.a_leader (a leader variable)
|
||||
rougail.a_dyn_family_value1.a_leadership.a_follower (a follower variable)
|
||||
rougail.a_dyn_family_value2 (a dynamic family for "value2")
|
||||
rougail.a_dyn_family_value2.a_leadership (a leader family)
|
||||
rougail.a_dyn_family_value2.a_leadership.a_leader (a leader variable)
|
||||
rougail.a_dyn_family_value2.a_leadership.a_follower (a follower variable)
|
||||
|
||||
We retrieve alls description of variables and families.
|
||||
|
||||
Let us distinguish the variables of the families
|
||||
------------------------------------------------
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
|
||||
RougailConfig['main_structural_directories'] = ["dist/"]
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
|
||||
def walk(config, level=0):
|
||||
for option in config:
|
||||
if option.isoptiondescription():
|
||||
typ = "family"
|
||||
else:
|
||||
typ = "variable"
|
||||
prefix = " " * level
|
||||
print(f"{prefix}{typ}: {option.description()}")
|
||||
if option.isoptiondescription():
|
||||
walk(option, level + 1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
walk(config)
|
||||
|
||||
Let's execute `script.py`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python3 script.py
|
||||
family: rougail
|
||||
variable: rougail.my_variable (a simple variable)
|
||||
family: rougail.a_family (a simple family)
|
||||
variable: rougail.a_family.my_variable (a simple variable inside the family)
|
||||
family: rougail.a_dyn_family_value1 (a dynamic family for "value1")
|
||||
family: rougail.a_dyn_family_value1.a_leadership (a leader family)
|
||||
variable: rougail.a_dyn_family_value1.a_leadership.a_leader (a leader variable)
|
||||
variable: rougail.a_dyn_family_value1.a_leadership.a_follower (a follower variable)
|
||||
family: rougail.a_dyn_family_value2 (a dynamic family for "value2")
|
||||
family: rougail.a_dyn_family_value2.a_leadership (a leader family)
|
||||
variable: rougail.a_dyn_family_value2.a_leadership.a_leader (a leader variable)
|
||||
variable: rougail.a_dyn_family_value2.a_leadership.a_follower (a follower variable)
|
||||
|
||||
Or if we want more precision:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
|
||||
RougailConfig['main_structural_directories'] = ["dist/"]
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
|
||||
def walk(config, level=0):
|
||||
for option in config:
|
||||
if option.isoptiondescription():
|
||||
if option.isleadership():
|
||||
typ = "leadership"
|
||||
elif option.isdynamic():
|
||||
typ = "dynamic family"
|
||||
else:
|
||||
typ = "family"
|
||||
else:
|
||||
if option.isleader():
|
||||
typ = "leader"
|
||||
elif option.isfollower():
|
||||
typ = "follower"
|
||||
else:
|
||||
typ = "option"
|
||||
if option.isdynamic():
|
||||
typ = f"dynamic {typ}"
|
||||
prefix = " " * level
|
||||
print(f"{prefix}{typ}: {option.description()}")
|
||||
if option.isoptiondescription():
|
||||
walk(option, level + 1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
walk(config)
|
||||
|
||||
Let's execute `script.py`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
family: rougail
|
||||
option: rougail.my_variable (a simple variable)
|
||||
family: rougail.a_family (a simple family)
|
||||
option: rougail.a_family.my_variable (a simple variable inside the family)
|
||||
dynamic family: rougail.a_dyn_family_value1 (a dynamic family for "value1")
|
||||
dynamic family: rougail.a_dyn_family_value1.a_leadership (a leader family)
|
||||
dynamic option: rougail.a_dyn_family_value1.a_leadership.a_leader (a leader variable)
|
||||
dynamic option: rougail.a_dyn_family_value1.a_leadership.a_follower (a follower variable)
|
||||
dynamic family: rougail.a_dyn_family_value2 (a dynamic family for "value2")
|
||||
dynamic family: rougail.a_dyn_family_value2.a_leadership (a leader family)
|
||||
dynamic option: rougail.a_dyn_family_value2.a_leadership.a_leader (a leader variable)
|
||||
dynamic option: rougail.a_dyn_family_value2.a_leadership.a_follower (a follower variable)
|
||||
|
||||
Get variable values
|
||||
-------------------
|
||||
|
||||
If we want to walk to get variables and their values:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
|
||||
RougailConfig['main_structural_directories'] = ["dist/"]
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
|
||||
def walk(config):
|
||||
for option in config:
|
||||
if option.isoptiondescription():
|
||||
walk(option)
|
||||
else:
|
||||
print(f"{option.description()}: {option.value.get()}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
walk(config)
|
||||
|
||||
Let's execute `script.py`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
rougail.my_variable (a simple variable): ['value1', 'value2']
|
||||
rougail.a_family.my_variable (a simple variable inside the family): my_value
|
||||
rougail.a_dyn_family_value1.a_leadership.a_leader (a leader variable): None
|
||||
rougail.a_dyn_family_value1.a_leadership.a_follower (a follower variable): None
|
||||
rougail.a_dyn_family_value2.a_leadership.a_leader (a leader variable): None
|
||||
rougail.a_dyn_family_value2.a_leadership.a_follower (a follower variable): None
|
||||
|
||||
Modify variable values
|
||||
----------------------
|
||||
|
||||
Some variables are mandatories but hasn't value. Here we set alls values:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
RougailConfig['main_structural_directories'] = ["dist/"]
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
|
||||
|
||||
def walk(config):
|
||||
for option in config:
|
||||
if option.isoptiondescription():
|
||||
walk(option)
|
||||
else:
|
||||
print(f"{option.description()}: {option.value.get()}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Mandatories variables without value:")
|
||||
print(config.value.mandatory())
|
||||
config.value.set("rougail.my_variable", ["value 5", "value 6"])
|
||||
config.value.set("rougail.a_dyn_family_value_5.a_leadership.a_leader", "value 1")
|
||||
config.value.set("rougail.a_dyn_family_value_5.a_leadership.a_follower", "value 2")
|
||||
config.value.set("rougail.a_dyn_family_value_6.a_leadership.a_leader", "value 3")
|
||||
config.value.set("rougail.a_dyn_family_value_6.a_leadership.a_follower", "value 4")
|
||||
print("Mandatories variables without value:")
|
||||
print(config.value.mandatory())
|
||||
walk(config)
|
||||
|
||||
|
||||
Let's execute `script.py`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
Mandatories variables without value:
|
||||
[<TiramisuOption path="rougail.a_dyn_family_value1.a_leadership.a_leader">, <TiramisuOption path="rougail.a_dyn_family_value1.a_leadership.a_follower">, <TiramisuOption path="rougail.a_dyn_family_value2.a_leadership.a_leader">, <TiramisuOption path="rougail.a_dyn_family_value2.a_leadership.a_follower">]
|
||||
Mandatories variables without value:
|
||||
[]
|
||||
rougail.my_variable (a simple variable): ['value 5', 'value 6']
|
||||
rougail.a_family.my_variable (a simple variable inside the family): my_value
|
||||
rougail.a_dyn_family_value_5.a_leadership.a_leader (a leader variable): value 1
|
||||
rougail.a_dyn_family_value_5.a_leadership.a_follower (a follower variable): value 2
|
||||
rougail.a_dyn_family_value_6.a_leadership.a_leader (a leader variable): value 3
|
||||
rougail.a_dyn_family_value_6.a_leadership.a_follower (a follower variable): value 4
|
||||
167
docs/library/rougailconfig_load_from_cli.rst
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
Load Rougail configuration from Rougail command line informations
|
||||
==================================================================
|
||||
|
||||
There is a lot you can do with the Rougail command line (rougail-cli), but sometimes you need to do a more advanced script.
|
||||
|
||||
Rather than duplicating the configuration, why not load the information from the configuration file, environment variables, or command line options?
|
||||
|
||||
We can loading a combination of source information but always in this order:
|
||||
|
||||
- configuration file
|
||||
- environment variables
|
||||
- commandline options
|
||||
|
||||
.. warning:: specific options reserve for command line (in namespace "cli") are not available in script
|
||||
|
||||
Then let's create an structual file:term:`structure file` :file:`dist/00-base.yml`:
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: the :file:`dist/00-base.yml` file content
|
||||
|
||||
\%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable: my_value_extra # a simple variable
|
||||
...
|
||||
|
||||
Command line configuration file
|
||||
-------------------------------
|
||||
|
||||
Create a command line configuration file :file:`.rougailcli.yml`:
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: the :file:`.rougailcli.yml` file content
|
||||
|
||||
---
|
||||
main_structural_directories: # directories where are place structural file
|
||||
- dist
|
||||
step.output: json # output is not console but json
|
||||
|
||||
Let's execute Rougail command line:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ rougail
|
||||
{
|
||||
"my_variable": "my_value_extra"
|
||||
}
|
||||
|
||||
Then, let's create the :term:`Tiramisu` objects via the following :file:`script.py` script:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail
|
||||
rougail = Rougail()
|
||||
try:
|
||||
config = rougail.run()
|
||||
print(config.value.get())
|
||||
except Exception as err:
|
||||
print(f"ERROR: {err}")
|
||||
exit(1)
|
||||
|
||||
Let's execute `script.py`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python3 script.py
|
||||
|
||||
ERROR: option "Directories where structural files are placed" is mandatory but has no value
|
||||
|
||||
As expected, the .rougailcli.yml file is not loaded because it is specific to the command line.
|
||||
|
||||
Let's modifying the script to do this:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
from rougail.cli.rougailconfig import load
|
||||
load(RougailConfig, yaml_file=".rougailcli.yml")
|
||||
rougail = Rougail()
|
||||
try:
|
||||
config = rougail.run()
|
||||
print(config.value.get())
|
||||
except Exception as err:
|
||||
print(f"ERROR: {err}")
|
||||
exit(1)
|
||||
|
||||
Let's execute `script.py`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python3 script.py
|
||||
{<TiramisuOption path="rougail">: {<TiramisuOption path="rougail.my_variable">: 'my_value_extra'}}
|
||||
|
||||
Environment variables
|
||||
---------------------
|
||||
|
||||
If we don't have .rougailcli.yml, it's possible to set option with environment variables, like this:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ env ROUGAILCLI_MAIN_STRUCTURAL_DIRECTORIES=dist/ ROUGAILCLI_STEP.OUTPUT=json ROUGAILCLI_MAIN_NAMESPACE=test bin/rougail
|
||||
{
|
||||
"test": {
|
||||
"my_variable": "my_value_extra"
|
||||
}
|
||||
}
|
||||
|
||||
Do the same with a script:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
from rougail.cli.rougailconfig import load
|
||||
load(RougailConfig, env_prefix="ROUGAILCLI")
|
||||
rougail = Rougail()
|
||||
try:
|
||||
config = rougail.run()
|
||||
print(config.value.get())
|
||||
except Exception as err:
|
||||
print(f"ERROR: {err}")
|
||||
exit(1)
|
||||
|
||||
Let's execute `script.py`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ env ROUGAILCLI_MAIN_STRUCTURAL_DIRECTORIES=dist/ ROUGAILCLI_STEP.OUTPUT=json ROUGAILCLI_MAIN_NAMESPACE=test python3 script.py
|
||||
{<TiramisuOption path="test">: {<TiramisuOption path="test.my_variable">: 'my_value_extra'}}
|
||||
|
||||
Command line option
|
||||
-------------------
|
||||
|
||||
To reproduce this:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
./bin/rougail --main_structural_directories dist/ --step.output json --main_namespace=new_test
|
||||
{
|
||||
"new_test": {
|
||||
"my_variable": "my_value_extra"
|
||||
}
|
||||
}
|
||||
|
||||
Do this script:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
from rougail.cli.rougailconfig import load
|
||||
load(RougailConfig, commandline=True)
|
||||
rougail = Rougail()
|
||||
try:
|
||||
config = rougail.run()
|
||||
print(config.value.get())
|
||||
except Exception as err:
|
||||
print(f"ERROR: {err}")
|
||||
exit(1)
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python3 script.py --main_structural_directories dist/ --step.output json --main_namespace=new_test
|
||||
{<TiramisuOption path="new_test">: {<TiramisuOption path="new_test.my_variable">: 'my_value_extra'}
|
||||
112
docs/library/tags.rst
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
Use tag informations
|
||||
====================
|
||||
|
||||
When we set tags for a variable, it will add :term:`Tiramisu` properties and informations.
|
||||
|
||||
We can filter those variables easily with tags.
|
||||
|
||||
First of all, create our structural file:
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: the :file:`dist/00-base.yml` file content
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
infra_name: my infra # Name of this infrastructure
|
||||
|
||||
server1: # the first server
|
||||
|
||||
internal_domain:
|
||||
description: Server domaine name
|
||||
type: domainname
|
||||
tags:
|
||||
- internal
|
||||
|
||||
external_domain:
|
||||
description: Domain name to access to this server for Internet
|
||||
type: domainname
|
||||
tags:
|
||||
- external
|
||||
|
||||
server2: # the second server
|
||||
|
||||
address:
|
||||
description: Server domaine name
|
||||
type: domainname
|
||||
tags:
|
||||
- internal
|
||||
...
|
||||
|
||||
Exclude variables with a specific tag
|
||||
-------------------------------------
|
||||
|
||||
To exclude variables with a specific tag is very easy. When the variable has tags, properties with same name are automaticly create.
|
||||
So exclude a tag means exclude variable with a particular property.
|
||||
|
||||
In this example we exclude variable with "internal" tag and display result of "server1" family:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
from pprint import pprint
|
||||
|
||||
RougailConfig['main_namespace'] = None
|
||||
RougailConfig['main_structural_directories'] = ['dist']
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
print("without filter:")
|
||||
pprint(config.option("server1").value.get())
|
||||
config.property.add('internal')
|
||||
print("with filter:")
|
||||
pprint(config.option("server1").value.get())
|
||||
|
||||
Let's execute `script.py`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python3 script.py
|
||||
without filter:
|
||||
{<TiramisuOption path="server1.external_domain">: None,
|
||||
<TiramisuOption path="server1.internal_domain">: None}
|
||||
with filter:
|
||||
{<TiramisuOption path="server1.external_domain">: None}
|
||||
|
||||
Only variable with a specific tag
|
||||
---------------------------------
|
||||
|
||||
It's more difficult to see only variable with a specific tag.
|
||||
|
||||
We have to walk through the configuration and retrieve variable with the selected tag.
|
||||
Tags are in properties but, are in information too.
|
||||
|
||||
Here is a smal script that walk that the configuration and "print" option with "internal" tag:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
|
||||
RougailConfig['main_structural_directories'] = ['dist']
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
|
||||
def walk(config):
|
||||
for option in config:
|
||||
if option.isoptiondescription():
|
||||
walk(option)
|
||||
elif "internal" in option.information.get('tags', []):
|
||||
print(option.description())
|
||||
|
||||
if __name__ == '__main__':
|
||||
walk(config)
|
||||
|
||||
Let's execute `script.py`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python3 script.py
|
||||
server1.internal_domain (Server domaine name)
|
||||
server2.address (Server domaine name)
|
||||
42
docs/library/upgrade.rst
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
Upgrade dictionnaries to upper version
|
||||
======================================
|
||||
|
||||
All dictionnaries has a format version number.
|
||||
When a new format version is proposed, it is possible to automatically convert the files to the new version.
|
||||
|
||||
We create a term:`structure file` named :file:`dict/01-upgrade.yml` with version 1.0:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
version: '1.0'
|
||||
my_variable:
|
||||
multi: true
|
||||
my_dyn_family:
|
||||
type: "dynamic"
|
||||
variable: my_variable
|
||||
a_variable:
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> from rougail import RougailUpgrade, RougailConfig
|
||||
>>> RougailConfig['main_structural_directories'] = ['dict']
|
||||
>>> upgrade = RougailUpgrade()
|
||||
>>> upgrade.load_dictionaries('dict_converted')
|
||||
|
||||
The term:`structure file` named :file:`dict_converted/01-upgrade.yml` is in version 1.1:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
version: '1.1'
|
||||
my_variable:
|
||||
multi: true
|
||||
my_dyn_family:
|
||||
type: dynamic
|
||||
a_variable: null
|
||||
dynamic:
|
||||
type: variable
|
||||
variable: my_variable
|
||||
propertyerror: false
|
||||
|
||||
390
docs/library/user_data.rst
Normal file
|
|
@ -0,0 +1,390 @@
|
|||
Load user data
|
||||
===============
|
||||
|
||||
User data are values setup by user for configuration variables.
|
||||
|
||||
There is differents types of user data for differents sources types.
|
||||
|
||||
We can cumulate user data loader.
|
||||
|
||||
For this section, we will use :file:`dict/00-base.yml` a structure file:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable: my value # My first variable
|
||||
|
||||
my_boolean_variable: true # My boolean variable
|
||||
|
||||
my_integer_variable: 1 # My integer variable
|
||||
|
||||
my_secret_variable:
|
||||
description: My secret variable
|
||||
type: secret
|
||||
|
||||
my_hidden_variable:
|
||||
description: My hidden variable
|
||||
hidden: true
|
||||
...
|
||||
|
||||
Here is the first script which is load this file:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
|
||||
RougailConfig["main_namespace"] = None
|
||||
RougailConfig["main_structural_directories"] = ["dist/"]
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
print(config.value.get())
|
||||
|
||||
Let's execute `script.py`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python3 script.py
|
||||
{<TiramisuOption path="my_variable">: 'my value', <TiramisuOption path="my_boolean_variable">: True, <TiramisuOption path="my_integer_variable">: 1, <TiramisuOption path="my_secret_variable">: None}
|
||||
|
||||
YAML
|
||||
----
|
||||
|
||||
We want to load this YAML file with value define by user:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
my_variable: a new value
|
||||
|
||||
my_boolean_variable: false
|
||||
|
||||
my_integer_variable: 10
|
||||
|
||||
my_secret_variable: MyVeryStrongPassword
|
||||
|
||||
Here is the script which is load user data from the YAML file:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
from rougail.user_data_yaml import RougailUserDataYaml
|
||||
|
||||
RougailConfig["main_namespace"] = None
|
||||
RougailConfig["main_structural_directories"] = ["dist/"]
|
||||
RougailConfig["step.user_data"] = ["yaml"]
|
||||
RougailConfig["yaml.filename"] = ["dist.yml"]
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
|
||||
user_data = RougailUserDataYaml(config).run()
|
||||
rougail.user_data(user_data)
|
||||
print(config.value.get())
|
||||
|
||||
Let's execute `script.py`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python3 script.py
|
||||
{<TiramisuOption path="my_variable">: 'a new value', <TiramisuOption path="my_boolean_variable">: False, <TiramisuOption path="my_integer_variable">: 10, <TiramisuOption path="my_secret_variable">: 'MyVeryStrongPassword'}
|
||||
|
||||
Set a secret in clear text file is not always a good idea.
|
||||
This is why the `yaml.file_with_secrets` parameter allows you to define whether files define in `yaml.filename` can contain a secret and which one:
|
||||
|
||||
- all: all file can contains secret
|
||||
- first: only the first file can contains secret
|
||||
- last: only the last file can contains secret
|
||||
- none: no file can contains secret
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
from rougail.user_data_yaml import RougailUserDataYaml
|
||||
|
||||
RougailConfig["main_namespace"] = None
|
||||
RougailConfig["main_structural_directories"] = ["dist/"]
|
||||
RougailConfig["step.user_data"] = ["yaml"]
|
||||
RougailConfig["yaml.filename"] = ["dist.yml"]
|
||||
RougailConfig["yaml.file_with_secrets"] = "none"
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
|
||||
user_data = RougailUserDataYaml(
|
||||
config,
|
||||
).run()
|
||||
rougail.user_data(user_data)
|
||||
print(config.value.get())
|
||||
|
||||
Let's execute `script.py`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python3 script.py
|
||||
{<TiramisuOption path="my_variable">: 'a new value', <TiramisuOption path="my_boolean_variable">: False, <TiramisuOption path="my_integer_variable">: 10, <TiramisuOption path="my_secret_variable">: None}
|
||||
|
||||
Environment variables
|
||||
---------------------
|
||||
|
||||
We can define use data from environment variables. The environment name is a "prefix" (ROUGAIL by default) with "_" and variable name in uppercase format.
|
||||
|
||||
For example:
|
||||
|
||||
- `my_variable` has `ROUGAIL_MY_VARIABLE` as a environment variable name
|
||||
- `my_family.my_variable` has `ROUGAIL_MY_FAMILY.MY_VARIABLE` as a environment variable name
|
||||
|
||||
Some shell doesn't allow dot in environment file. In this case use the command "env".
|
||||
|
||||
For example: `env ROUGAIL_MY_FAMILY.MY_VARIABLE="value" ./script.py`.
|
||||
|
||||
Here is the script:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
from rougail.user_data_environment import RougailUserDataEnvironment
|
||||
|
||||
RougailConfig["main_namespace"] = None
|
||||
RougailConfig["main_structural_directories"] = ["dist/"]
|
||||
RougailConfig["step.user_data"] = ["environment"]
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
|
||||
user_data = RougailUserDataEnvironment(config).run()
|
||||
rougail.user_data(user_data)
|
||||
print(config.value.get())
|
||||
|
||||
Let's execute `script.py`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
env ROUGAIL_MY_VARIABLE="a new value" ROUGAIL_MY_BOOLEAN_VARIABLE="False" ROUGAIL_MY_INTEGER_VARIABLE=10 ROUGAIL_MY_SECRET_VARIABLE="MyVeryStrongPassword" python script.py
|
||||
{<TiramisuOption path="my_variable">: 'a new value', <TiramisuOption path="my_boolean_variable">: False, <TiramisuOption path="my_integer_variable">: 10, <TiramisuOption path="my_secret_variable">: 'MyVeryStrongPassword'}
|
||||
|
||||
We can redefine the prefix with `environment.default_environment_name` (prefix is always uppercase characters):
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
from rougail.user_data_environment import RougailUserDataEnvironment
|
||||
|
||||
RougailConfig["main_namespace"] = None
|
||||
RougailConfig["main_structural_directories"] = ["dist/"]
|
||||
RougailConfig["step.user_data"] = ["environment"]
|
||||
RougailConfig["environment.default_environment_name"] = "EX"
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
|
||||
user_data = RougailUserDataEnvironment(config).run()
|
||||
rougail.user_data(user_data)
|
||||
print(config.value.get())
|
||||
|
||||
Let's execute `script.py`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
env EX_MY_VARIABLE="a new value" EX_MY_BOOLEAN_VARIABLE="False" EX_MY_INTEGER_VARIABLE=10 EX_MY_SECRET_VARIABLE="MyVeryStrongPassword" python script.py
|
||||
{<TiramisuOption path="my_variable">: 'a new value', <TiramisuOption path="my_boolean_variable">: False, <TiramisuOption path="my_integer_variable">: 10, <TiramisuOption path="my_secret_variable">: 'MyVeryStrongPassword'}
|
||||
|
||||
If you define a `main_namespace` or `extra_namespaces`, the `environment.default_environment_name` is automaticly define with the name of the namespace in uppercase. And the separator is no more "_" but ".":
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
from rougail.user_data_environment import RougailUserDataEnvironment
|
||||
|
||||
RougailConfig["main_namespace"] = "main"
|
||||
RougailConfig["main_structural_directories"] = ["dist/"]
|
||||
RougailConfig["step.user_data"] = ["environment"]
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
|
||||
user_data = RougailUserDataEnvironment(config).run()
|
||||
rougail.user_data(user_data)
|
||||
print(config.value.get())
|
||||
|
||||
Let's execute `script.py`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
env MAIN.MY_VARIABLE="a new value" MAIN.MY_BOOLEAN_VARIABLE="False" MAIN.MY_INTEGER_VARIABLE=10 MAIN.MY_SECRET_VARIABLE="MyVeryStrongPassword" python script.py
|
||||
{<TiramisuOption path="main">: {<TiramisuOption path="main.my_variable">: 'a new value', <TiramisuOption path="main.my_boolean_variable">: False, <TiramisuOption path="main.my_integer_variable">: 10, <TiramisuOption path="main.my_secret_variable">: 'MyVeryStrongPassword'}}
|
||||
|
||||
Set a secret in clear variable environment is not always a good idea.
|
||||
This is why the `environment.with_secrets` parameter allows you to reject secret from environment variable:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
from rougail.user_data_environment import RougailUserDataEnvironment
|
||||
|
||||
RougailConfig["main_namespace"] = None
|
||||
RougailConfig["main_structural_directories"] = ["dist/"]
|
||||
RougailConfig["step.user_data"] = ["environment"]
|
||||
RougailConfig["environment.with_secrets"] = False
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
|
||||
user_data = RougailUserDataEnvironment(config).run()
|
||||
rougail.user_data(user_data)
|
||||
print(config.value.get())
|
||||
|
||||
Let's execute `script.py`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
env ROUGAIL_MY_VARIABLE="a new value" ROUGAIL_MY_BOOLEAN_VARIABLE="False" ROUGAIL_MY_INTEGER_VARIABLE=10 ROUGAIL_MY_SECRET_VARIABLE="MyVeryStrongPassword" python script.py
|
||||
{<TiramisuOption path="my_variable">: 'a new value', <TiramisuOption path="my_boolean_variable">: False, <TiramisuOption path="my_integer_variable">: 10, <TiramisuOption path="my_secret_variable">: None}
|
||||
|
||||
Comand line parser user data
|
||||
----------------------------
|
||||
|
||||
Value can be define directly with command line arguments:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
from rougail.user_data_commandline import RougailUserDataCommandline
|
||||
|
||||
RougailConfig["main_namespace"] = None
|
||||
RougailConfig["main_structural_directories"] = ["dist/"]
|
||||
RougailConfig["step.user_data"] = ["commandline"]
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
|
||||
user_data = RougailUserDataCommandline(
|
||||
config,
|
||||
).run()
|
||||
rougail.user_data(user_data)
|
||||
print(config.value.get())
|
||||
|
||||
Let's execute `script.py` to display help:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python script.py -h
|
||||
usage: script.py [-h] --my_variable [MY_VARIABLE] --my_boolean_variable --no-my_boolean_variable --my_integer_variable [MY_INTEGER_VARIABLE] --my_secret_variable MY_SECRET_VARIABLE
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--my_variable [MY_VARIABLE]
|
||||
my_variable (My first variable) (default: my value)
|
||||
--my_boolean_variable
|
||||
my_boolean_variable (My boolean variable) (default: True)
|
||||
--no-my_boolean_variable
|
||||
--my_integer_variable [MY_INTEGER_VARIABLE]
|
||||
my_integer_variable (My integer variable) (default: 1)
|
||||
--my_secret_variable MY_SECRET_VARIABLE
|
||||
my_secret_variable (My secret variable)
|
||||
{<TiramisuOption path="my_variable">: 'my value', <TiramisuOption path="my_boolean_variable">: True, <TiramisuOption path="my_integer_variable">: 1, <TiramisuOption path="my_secret_variable">: None}
|
||||
|
||||
|
||||
And now with modified value:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python script.py --my_variable "a new value" --no-my_boolean_variable --my_integer_variable 10 --my_secret_variable MyVeryStrongPassword
|
||||
{<TiramisuOption path="my_variable">: 'a new value', <TiramisuOption path="my_boolean_variable">: False, <TiramisuOption path="my_integer_variable">: 10, <TiramisuOption path="my_secret_variable">: 'MyVeryStrongPassword'}
|
||||
|
||||
Boolean variable has a special behavour. To set False you need to add --no-VARIABLE, to set True you need to add --VARIABLE parameter.
|
||||
|
||||
.. ansible,bitwarden,questionary
|
||||
|
||||
Combine user data
|
||||
------------------
|
||||
|
||||
You can combine user data, for example if you want to load data from environment and/or command line argument:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
from rougail.user_data_environment import RougailUserDataEnvironment
|
||||
from rougail.user_data_commandline import RougailUserDataCommandline
|
||||
|
||||
RougailConfig["main_namespace"] = None
|
||||
RougailConfig["main_structural_directories"] = ["dist/"]
|
||||
RougailConfig["step.user_data"] = ["environment", "commandline"]
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
|
||||
user_data = []
|
||||
user_data.extend(RougailUserDataEnvironment(
|
||||
config,
|
||||
).run())
|
||||
user_data.extend(RougailUserDataCommandline(
|
||||
config,
|
||||
).run())
|
||||
rougail.user_data(user_data)
|
||||
print(config.value.get())
|
||||
|
||||
Let's execute `script.py` with environment variable and commandline arguments:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ env ROUGAIL_MY_VARIABLE="a new value" ROUGAIL_MY_BOOLEAN_VARIABLE="False" python script.py --my_integer_variable 10 --my_secret_variable MyVeryStrongPassword
|
||||
{<TiramisuOption path="my_variable">: 'a new value', <TiramisuOption path="my_boolean_variable">: False, <TiramisuOption path="my_integer_variable">: 10, <TiramisuOption path="my_secret_variable">: 'MyVeryStrongPassword'}
|
||||
|
||||
If the value of a variable is define with an environment variable and commandline argument, the value is the value of the last user data define:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ env ROUGAIL_MY_VARIABLE="not a new" python script.py --my_variable "a new value" --no-my_boolean_variable --my_integer_variable 10 --my_secret_variable MyVeryStrongPassword
|
||||
{<TiramisuOption path="my_variable">: 'a new value', <TiramisuOption path="my_boolean_variable">: False, <TiramisuOption path="my_integer_variable">: 10, <TiramisuOption path="my_secret_variable">: 'MyVeryStrongPassword'}
|
||||
|
||||
Manage errors and warnings
|
||||
--------------------------
|
||||
|
||||
Recreate a script with environnement variable support which is display the return of user_data function:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: the :file:`script.py` file content
|
||||
|
||||
from rougail import Rougail, RougailConfig
|
||||
from rougail.user_data_environment import RougailUserDataEnvironment
|
||||
|
||||
RougailConfig["main_namespace"] = None
|
||||
RougailConfig["main_structural_directories"] = ["dist/"]
|
||||
RougailConfig["step.user_data"] = ["environment"]
|
||||
RougailConfig["environment.with_secrets"] = False
|
||||
rougail = Rougail()
|
||||
config = rougail.run()
|
||||
|
||||
user_data = RougailUserDataEnvironment(
|
||||
config,
|
||||
).run()
|
||||
print(rougail.user_data(user_data))
|
||||
|
||||
Try to load the value an unknown variable:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ env ROUGAIL_UNKNOWN_VARIABLE="a value" python script.py
|
||||
{'errors': [], 'warnings': ['variable or family "unknown_variable" does not exist, it will be ignored when loading from environment variable']}
|
||||
|
||||
As you can see, a warnings is return.
|
||||
|
||||
Try to load the value of an hidden variable:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ env ROUGAIL_MY_HIDDEN_VARIABLE="a value" python script.py
|
||||
{'errors': [], 'warnings': ['variable "my_hidden_variable" (My hidden variable) is hidden, it will be ignored when loading from environment variable']}
|
||||
|
||||
Finally if a try to change the value of a secret, which is not allowed:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ env ROUGAIL_MY_SECRET_VARIABLE="MyVeryStrongPassword" python script.py
|
||||
{'errors': ['the variable "my_secret_variable" contains secrets and should not be defined in environment variable'], 'warnings': []}
|
||||
|
||||
An error is generated.
|
||||
230
docs/output/ansible.rst
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
Generate Ansible inventory
|
||||
==========================
|
||||
|
||||
.. note::
|
||||
|
||||
| **Path**: ansible
|
||||
| `*disabled*`
|
||||
| **Disabled**: when the variable "select for output" (step.output) is accessible and hasn't the value "ansible".
|
||||
|
||||
|
||||
|
||||
.. list-table::
|
||||
|
||||
* - Variable
|
||||
- Description
|
||||
|
||||
* - **ansible.output**
|
||||
|
||||
`choice <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory`
|
||||
|
||||
**Command line**:
|
||||
|
||||
--ansible.output
|
||||
|
||||
**Environment variable**: ROUGAILCLI_ANSIBLE.OUTPUT
|
||||
- Output type.
|
||||
|
||||
**Choices**:
|
||||
|
||||
|
||||
|
||||
- inventory **← (default)**
|
||||
|
||||
- doc
|
||||
|
||||
* - **ansible.host_namespace**
|
||||
|
||||
`string <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory`
|
||||
|
||||
**Command line**:
|
||||
|
||||
--ansible.host_namespace
|
||||
|
||||
**Environment variable**: ROUGAILCLI_ANSIBLE.HOST_NAMESPACE
|
||||
- Namespace with host values.
|
||||
|
||||
**Default**: hosts
|
||||
|
||||
Doc configuration
|
||||
-----------------
|
||||
|
||||
.. note::
|
||||
|
||||
| **Path**: ansible.doc
|
||||
| `*disabled*`
|
||||
| **Disabled**: when the variable "Output type" (ansible.output) hasn't the value "doc".
|
||||
|
||||
|
||||
|
||||
.. list-table::
|
||||
|
||||
* - Variable
|
||||
- Description
|
||||
|
||||
* - **ansible.doc.project_name**
|
||||
|
||||
`string <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory`
|
||||
|
||||
**Command line**:
|
||||
|
||||
--ansible.doc.project_name
|
||||
|
||||
**Environment variable**: ROUGAILCLI_ANSIBLE.DOC.PROJECT_NAME
|
||||
- Ansible project name.
|
||||
|
||||
* - **ansible.doc.author**
|
||||
|
||||
`string <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory`
|
||||
|
||||
**Command line**:
|
||||
|
||||
--ansible.doc.author
|
||||
|
||||
**Environment variable**: ROUGAILCLI_ANSIBLE.DOC.AUTHOR
|
||||
- Ansible author name.
|
||||
|
||||
* - **ansible.doc.output_format**
|
||||
|
||||
`choice <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory`
|
||||
|
||||
**Command line**:
|
||||
|
||||
--ansible.doc.output_format
|
||||
|
||||
**Environment variable**: ROUGAILCLI_ANSIBLE.DOC.OUTPUT_FORMAT
|
||||
- The output format of the generated documentation.
|
||||
|
||||
**Choices**:
|
||||
|
||||
|
||||
|
||||
- console **← (default)**
|
||||
|
||||
- asciidoc
|
||||
|
||||
- html
|
||||
|
||||
- github
|
||||
|
||||
- gitlab
|
||||
|
||||
- restructuredtext
|
||||
|
||||
- json
|
||||
|
||||
* - **ansible.doc.collection_type**
|
||||
|
||||
`choice <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory`
|
||||
|
||||
**Command line**:
|
||||
|
||||
--ansible.doc.collection_type
|
||||
|
||||
**Environment variable**: ROUGAILCLI_ANSIBLE.DOC.COLLECTION_TYPE
|
||||
- Collection contents.
|
||||
|
||||
**Choices**:
|
||||
|
||||
|
||||
|
||||
- auto **← (default)**
|
||||
|
||||
- playbooks
|
||||
|
||||
- roles
|
||||
|
||||
Playbooks informations
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. note::
|
||||
|
||||
| This family contains lists of variable blocks.
|
||||
| **Path**: ansible.doc.playbooks
|
||||
| `*disabled*`
|
||||
| **Disabled**: if the content is a role.
|
||||
|
||||
|
||||
|
||||
.. list-table::
|
||||
|
||||
* - Variable
|
||||
- Description
|
||||
|
||||
* - **ansible.doc.playbooks.name**
|
||||
|
||||
`string <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `multiple` `unique`
|
||||
|
||||
**Command line**:
|
||||
|
||||
--ansible.doc.playbooks.name
|
||||
|
||||
**Environment variable**: ROUGAILCLI_ANSIBLE.DOC.PLAYBOOKS.NAME
|
||||
- Playbook name.
|
||||
|
||||
Playbooks are placed in the playbooks/ directory. By default, the description of the "type" is used as the playbook name in the generated example. It is possible to customize this description here.
|
||||
|
||||
* - **ansible.doc.playbooks.description**
|
||||
|
||||
`string <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory`
|
||||
|
||||
**Command line**:
|
||||
|
||||
--ansible.doc.playbooks.description
|
||||
|
||||
**Environment variable**: ROUGAILCLI_ANSIBLE.DOC.PLAYBOOKS.DESCRIPTION
|
||||
- Playbook description.
|
||||
|
||||
Inventory configuration
|
||||
-----------------------
|
||||
|
||||
.. note::
|
||||
|
||||
| **Path**: ansible.inventory
|
||||
| `*disabled*`
|
||||
| **Disabled**: when the variable "Output type" (ansible.output) hasn't the value "inventory".
|
||||
|
||||
|
||||
|
||||
.. list-table::
|
||||
|
||||
* - Variable
|
||||
- Description
|
||||
|
||||
* - **ansible.inventory.no_namespace_in_vars**
|
||||
|
||||
`boolean <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory`
|
||||
|
||||
**Command line**:
|
||||
|
||||
|
||||
|
||||
- --ansible.inventory.no_namespace_in_vars
|
||||
|
||||
- --ansible.inventory.no-no_namespace_in_vars
|
||||
|
||||
|
||||
|
||||
**Environment variable**: ROUGAILCLI_ANSIBLE.INVENTORY.NO_NAMESPACE_IN_VARS
|
||||
- Remove namespace name in host vars.
|
||||
|
||||
**Default**: false
|
||||
|
||||
* - **ansible.inventory.export_warnings**
|
||||
|
||||
`boolean <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory`
|
||||
|
||||
**Command line**:
|
||||
|
||||
|
||||
|
||||
- --ansible.inventory.export_warnings
|
||||
|
||||
- --ansible.inventory.no-export_warnings
|
||||
|
||||
|
||||
|
||||
**Environment variable**: ROUGAILCLI_ANSIBLE.INVENTORY.EXPORT_WARNINGS
|
||||
- Displays warnings inside Ansible exportation datas.
|
||||
|
||||
**Default**: true
|
||||
87
docs/output/display.rst
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
Display variables and values
|
||||
============================
|
||||
|
||||
.. note::
|
||||
|
||||
| Find all the variables and their values in your configuration (structural and user data). Additional informations are available, such as the default value, the location where the value is loaded, etc.
|
||||
| **Path**: display
|
||||
| `*disabled*`
|
||||
| **Disabled**: if display is not set in "select for output" (step.output).
|
||||
|
||||
|
||||
|
||||
.. list-table::
|
||||
|
||||
* - Variable
|
||||
- Description
|
||||
|
||||
* - **display.output_format**
|
||||
|
||||
`choice <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory`
|
||||
|
||||
**Command line**:
|
||||
|
||||
--display.output_format
|
||||
|
||||
**Environment variable**: ROUGAILCLI_DISPLAY.OUTPUT_FORMAT
|
||||
- The output format for displaying variables.
|
||||
|
||||
**Choices**:
|
||||
|
||||
|
||||
|
||||
- console **← (default)**
|
||||
|
||||
- github
|
||||
|
||||
- gitlab
|
||||
|
||||
* - **display.show_secrets**
|
||||
|
||||
`boolean <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory`
|
||||
|
||||
**Command line**:
|
||||
|
||||
|
||||
|
||||
- --display.show_secrets
|
||||
|
||||
- --display.no-show_secrets
|
||||
|
||||
|
||||
|
||||
**Environment variable**: ROUGAILCLI_DISPLAY.SHOW_SECRETS
|
||||
- Show secrets instead of obscuring them.
|
||||
|
||||
**Default**: false
|
||||
|
||||
Specific configuration for console output
|
||||
-----------------------------------------
|
||||
|
||||
.. note::
|
||||
|
||||
| **Path**: display.console
|
||||
| `*disabled*`
|
||||
| **Disabled**: when the variable "The output format for displaying variables" (display.output_format) hasn't the value "console".
|
||||
|
||||
|
||||
|
||||
.. list-table::
|
||||
|
||||
* - Variable
|
||||
- Description
|
||||
|
||||
* - **display.console.max_width**
|
||||
|
||||
`integer <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__
|
||||
|
||||
**Command line**:
|
||||
|
||||
--display.console.max_width
|
||||
|
||||
**Environment variable**: ROUGAILCLI_DISPLAY.CONSOLE.MAX_WIDTH
|
||||
- Maximum number of characters per line.
|
||||
|
||||
Null means unlimited.
|
||||
|
||||
**Validator**: the minimum value is 50
|
||||
381
docs/output/doc.rst
Normal file
|
|
@ -0,0 +1,381 @@
|
|||
Generate documentation from structural files
|
||||
============================================
|
||||
|
||||
.. note::
|
||||
|
||||
| The structural files contain all the information related to the variables. This output generates the documentation for all or some of these variables.
|
||||
| **Path**: doc
|
||||
| `*disabled*`
|
||||
| **Disabled**: if "select for output" (step.output) is not doc.
|
||||
|
||||
|
||||
|
||||
.. list-table::
|
||||
|
||||
* - Variable
|
||||
- Description
|
||||
|
||||
* - **doc.output_format**
|
||||
|
||||
`choice <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory`
|
||||
|
||||
**Command line**:
|
||||
|
||||
-do, --doc.output_format
|
||||
|
||||
**Environment variable**: ROUGAILCLI_DOC.OUTPUT_FORMAT
|
||||
- The output format of the generated documentation.
|
||||
|
||||
**Choices**:
|
||||
|
||||
|
||||
|
||||
- console **← (default)**
|
||||
|
||||
- asciidoc
|
||||
|
||||
- html
|
||||
|
||||
- github
|
||||
|
||||
- gitlab
|
||||
|
||||
- restructuredtext
|
||||
|
||||
- json
|
||||
|
||||
* - **doc.tabular_template**
|
||||
|
||||
`choice <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory` `*disabled*`
|
||||
|
||||
**Command line**:
|
||||
|
||||
-dm, --doc.tabular_template
|
||||
|
||||
**Environment variable**: ROUGAILCLI_DOC.TABULAR_TEMPLATE
|
||||
- Generate document with this tabular model.
|
||||
|
||||
The variables are documented with a tabular view. A template selection allows you to choose the content of each column.
|
||||
|
||||
**Choices**:
|
||||
|
||||
|
||||
|
||||
- two_columns **← (default)**
|
||||
|
||||
- three_columns
|
||||
|
||||
- four_columns
|
||||
|
||||
- five_columns
|
||||
|
||||
- six_columns
|
||||
|
||||
|
||||
|
||||
**Disabled**: "the output format of the generated documentation" (doc.output_format) in json is not compatible with this variable.
|
||||
|
||||
* - **doc.contents**
|
||||
|
||||
`choice <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `multiple` `mandatory` `*hidden*` `unique`
|
||||
|
||||
**Command line**:
|
||||
|
||||
-dc, --doc.contents
|
||||
|
||||
**Environment variable**: ROUGAILCLI_DOC.CONTENTS
|
||||
- Generated content.
|
||||
|
||||
You can generate three type of document. All variables ("variables"), an example file in YAML format ("example") or change log ("changelog").
|
||||
|
||||
**Choices**:
|
||||
|
||||
|
||||
|
||||
- variables **← (default)**
|
||||
|
||||
- example
|
||||
|
||||
- changelog
|
||||
|
||||
|
||||
|
||||
**Hidden**: "the output format of the generated documentation" (doc.output_format) in json is not compatible with changelog or example "generated content" (doc.contents).
|
||||
|
||||
* - **doc.title_level**
|
||||
|
||||
`integer <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory`
|
||||
|
||||
**Command line**:
|
||||
|
||||
-dt, --doc.title_level
|
||||
|
||||
**Environment variable**: ROUGAILCLI_DOC.TITLE_LEVEL
|
||||
- Starting title level.
|
||||
|
||||
**Default**: 1
|
||||
|
||||
* - **doc.default_values**
|
||||
|
||||
`boolean <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory`
|
||||
|
||||
**Command line**:
|
||||
|
||||
|
||||
|
||||
- --doc.default_values
|
||||
|
||||
- --doc.no-default_values
|
||||
|
||||
|
||||
|
||||
**Environment variable**: ROUGAILCLI_DOC.DEFAULT_VALUES
|
||||
- Modify values to document all variables.
|
||||
|
||||
To document homogeneous elements type or dynamic family variables, it is sometimes necessary to generate values, which can change the values in the configuration. Be careful if you reuse this configuration.
|
||||
|
||||
**Default**: true
|
||||
|
||||
* - **doc.true_color**
|
||||
|
||||
`boolean <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory` `*disabled*`
|
||||
|
||||
**Command line**:
|
||||
|
||||
|
||||
|
||||
- --doc.true_color
|
||||
|
||||
- --doc.no-true_color
|
||||
|
||||
|
||||
|
||||
**Environment variable**: ROUGAILCLI_DOC.TRUE_COLOR
|
||||
- Display documentation in console always with true color terminal.
|
||||
|
||||
**Default**: false
|
||||
|
||||
**Disabled**: when the variable "the output format of the generated documentation" (doc.output_format) hasn't the value "console".
|
||||
|
||||
The variables in this family are documented in another file
|
||||
-----------------------------------------------------------
|
||||
|
||||
.. note::
|
||||
|
||||
| If you separate the variables into different files, the links between the variables will break. Therefore, you must define different filenames for the files containing these variables.
|
||||
| This family contains lists of variable blocks.
|
||||
| **Path**: doc.other_root_filenames
|
||||
|
||||
|
||||
|
||||
.. list-table::
|
||||
|
||||
* - Variable
|
||||
- Description
|
||||
|
||||
* - **doc.other_root_filenames.root_path**
|
||||
|
||||
`string <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `multiple` `unique`
|
||||
|
||||
**Command line**:
|
||||
|
||||
--doc.other_root_filenames.root_path
|
||||
|
||||
**Environment variable**: ROUGAILCLI_DOC.OTHER_ROOT_FILENAMES.ROOT_PATH
|
||||
- This file contains child variables of the family.
|
||||
|
||||
* - **doc.other_root_filenames.root_doc_path**
|
||||
|
||||
`string <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__
|
||||
|
||||
**Command line**:
|
||||
|
||||
--doc.other_root_filenames.root_doc_path
|
||||
|
||||
**Environment variable**: ROUGAILCLI_DOC.OTHER_ROOT_FILENAMES.ROOT_DOC_PATH
|
||||
- Name of the file.
|
||||
|
||||
|
||||
|
||||
.. list-table::
|
||||
|
||||
* - Variable
|
||||
- Description
|
||||
|
||||
* - **doc.document_a_type**
|
||||
|
||||
`boolean <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory`
|
||||
|
||||
**Command line**:
|
||||
|
||||
|
||||
|
||||
- --doc.document_a_type
|
||||
|
||||
- --doc.no-document_a_type
|
||||
|
||||
|
||||
|
||||
**Environment variable**: ROUGAILCLI_DOC.DOCUMENT_A_TYPE
|
||||
- Documentation a structural type.
|
||||
|
||||
**Default**: false
|
||||
|
||||
Variables and changelog documentation
|
||||
-------------------------------------
|
||||
|
||||
.. note::
|
||||
|
||||
| **Path**: doc.tabulars
|
||||
| `*disabled*`
|
||||
| **Disabled**: if "the output format of the generated documentation" (doc.output_format) is json or "generated content" (doc.contents) hasn't variables or changelog.
|
||||
|
||||
|
||||
|
||||
.. list-table::
|
||||
|
||||
* - Variable
|
||||
- Description
|
||||
|
||||
* - **doc.tabulars.without_family**
|
||||
|
||||
`boolean <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory`
|
||||
|
||||
**Command line**:
|
||||
|
||||
|
||||
|
||||
- -df, --doc.tabulars.without_family
|
||||
|
||||
- -ndf, --doc.tabulars.no-without_family
|
||||
|
||||
|
||||
|
||||
**Environment variable**: ROUGAILCLI_DOC.TABULARS.WITHOUT_FAMILY
|
||||
- Do not add families in documentation.
|
||||
|
||||
**Default**: false
|
||||
|
||||
* - **doc.tabulars.with_commandline**
|
||||
|
||||
`boolean <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory`
|
||||
|
||||
**Environment variable**: ROUGAILCLI_DOC.TABULARS.WITH_COMMANDLINE
|
||||
- Add command line informations in documentation.
|
||||
|
||||
**Default**: false
|
||||
|
||||
* - **doc.tabulars.with_environment**
|
||||
|
||||
`boolean <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory`
|
||||
|
||||
**Command line**:
|
||||
|
||||
|
||||
|
||||
- -de, --doc.tabulars.with_environment
|
||||
|
||||
- -nde, --doc.tabulars.no-with_environment
|
||||
|
||||
|
||||
|
||||
**Environment variable**: ROUGAILCLI_DOC.TABULARS.WITH_ENVIRONMENT
|
||||
- Add environment variable informations in documentation.
|
||||
|
||||
**Default**: false
|
||||
|
||||
* - **doc.tabulars.environment_prefix**
|
||||
|
||||
`string <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `*disabled*`
|
||||
|
||||
**Command line**:
|
||||
|
||||
-dv, --doc.tabulars.environment_prefix
|
||||
|
||||
**Environment variable**: ROUGAILCLI_DOC.TABULARS.ENVIRONMENT_PREFIX
|
||||
- Environment variables prefix name.
|
||||
|
||||
**Validator**: should only use uppercase characters
|
||||
|
||||
**Default**: ROUGAIL
|
||||
|
||||
**Disabled**: when the variable "add environment variable informations in documentation" (doc.tabulars.with_environment) has the value "false".
|
||||
|
||||
Changelog documentation
|
||||
-----------------------
|
||||
|
||||
.. note::
|
||||
|
||||
| **Path**: doc.changelog
|
||||
| `*disabled*`
|
||||
| **Disabled**: if changelog in not in "generated content" (doc.contents).
|
||||
|
||||
|
||||
|
||||
.. list-table::
|
||||
|
||||
* - Variable
|
||||
- Description
|
||||
|
||||
* - **doc.changelog.previous_json_file**
|
||||
|
||||
`string <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory`
|
||||
|
||||
**Command line**:
|
||||
|
||||
-dp, --doc.changelog.previous_json_file
|
||||
|
||||
**Environment variable**: ROUGAILCLI_DOC.CHANGELOG.PREVIOUS_JSON_FILE
|
||||
- Previous description file in JSON format.
|
||||
|
||||
To generate the changelog, you need to compare the old list of variables (in json format) with the current variables.
|
||||
|
||||
Examples configuration
|
||||
----------------------
|
||||
|
||||
.. note::
|
||||
|
||||
| **Path**: doc.examples
|
||||
| `*disabled*`
|
||||
| **Disabled**: if example is not in "generated content" (doc.contents).
|
||||
|
||||
|
||||
|
||||
.. list-table::
|
||||
|
||||
* - Variable
|
||||
- Description
|
||||
|
||||
* - **doc.examples.comment**
|
||||
|
||||
`boolean <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory`
|
||||
|
||||
**Command line**:
|
||||
|
||||
|
||||
|
||||
- -dx, --doc.examples.comment
|
||||
|
||||
- -ndx, --doc.examples.no-comment
|
||||
|
||||
|
||||
|
||||
**Environment variable**: ROUGAILCLI_DOC.EXAMPLES.COMMENT
|
||||
- Add description of variables and families when generate examples.
|
||||
|
||||
**Default**: false
|
||||
|
||||
* - **doc.examples.comment_column**
|
||||
|
||||
`integer <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory` `*disabled*`
|
||||
|
||||
**Command line**:
|
||||
|
||||
--doc.examples.comment_column
|
||||
|
||||
**Environment variable**: ROUGAILCLI_DOC.EXAMPLES.COMMENT_COLUMN
|
||||
- Comment in examples starts at column.
|
||||
|
||||
**Default**: 30
|
||||
|
||||
**Disabled**: when the variable "add description of variables and families when generate examples" (doc.examples.comment) has the value "false".
|
||||
29
docs/output/formatter.rst
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
Reformat the structure files
|
||||
============================
|
||||
|
||||
.. note::
|
||||
|
||||
| The structure file will be formatted according to a set of rules: empty line between each variable, short-hand notation whenever possible, attribute order, re-indentation (especially for Jinja2 templates), ...
|
||||
| **Path**: formatter
|
||||
| `*disabled*`
|
||||
| **Disabled**: if formatter is not set in "select for output" (step.output).
|
||||
|
||||
|
||||
|
||||
.. list-table::
|
||||
|
||||
* - Variable
|
||||
- Description
|
||||
|
||||
* - **formatter.line_width**
|
||||
|
||||
`integer <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory`
|
||||
|
||||
**Command line**:
|
||||
|
||||
--formatter.line_width
|
||||
|
||||
**Environment variable**: ROUGAILCLI_FORMATTER.LINE_WIDTH
|
||||
- Maximum line size.
|
||||
|
||||
**Default**: 120
|
||||
17
docs/output/index.rst
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
Output modules
|
||||
======================
|
||||
|
||||
Rougail is a collections of modules in order to adjust functionalities to your needs.
|
||||
|
||||
:term:`Output` is one of category of subjects. The goal is to display, export or document variable and value to meet the needs of the :term:`integrator` or :term:`operator`.
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
:caption: Available output
|
||||
|
||||
display
|
||||
table
|
||||
doc
|
||||
formatter
|
||||
ansible
|
||||
json
|
||||
3
docs/output/json.rst
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
Export variables and values to JSON
|
||||
===================================
|
||||
|
||||
98
docs/output/table.rst
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
Displays the data in a table
|
||||
============================
|
||||
|
||||
.. note::
|
||||
|
||||
| The goal is not to display all the variables in the configuration, but only a selection using the labeling mechanism.
|
||||
| **Path**: table
|
||||
| `*disabled*`
|
||||
| **Disabled**: if table is not set in "select for output" (step.output).
|
||||
|
||||
|
||||
|
||||
.. list-table::
|
||||
|
||||
* - Variable
|
||||
- Description
|
||||
|
||||
* - **table.first_column**
|
||||
|
||||
`choice <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory`
|
||||
|
||||
**Command line**:
|
||||
|
||||
--table.first_column
|
||||
|
||||
**Environment variable**: ROUGAILCLI_TABLE.FIRST_COLUMN
|
||||
- Content of the first column.
|
||||
|
||||
**Validator**: Tag name must not have the same name has first column
|
||||
|
||||
**Choices**:
|
||||
|
||||
|
||||
|
||||
- description
|
||||
|
||||
- namespace
|
||||
|
||||
|
||||
|
||||
**Default**: First column is description if "Tag names" (table.columns) has only one value, otherwise it's namespace.
|
||||
|
||||
* - **table.columns**
|
||||
|
||||
`string <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `multiple` `mandatory` `unique`
|
||||
|
||||
**Command line**:
|
||||
|
||||
--table.columns
|
||||
|
||||
**Environment variable**: ROUGAILCLI_TABLE.COLUMNS
|
||||
- Tag names.
|
||||
|
||||
Each tag creates a column. The content of the columns comes from the variables with the defined tags.
|
||||
|
||||
* - **table.output_format**
|
||||
|
||||
`choice <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory`
|
||||
|
||||
**Command line**:
|
||||
|
||||
--table.output_format
|
||||
|
||||
**Environment variable**: ROUGAILCLI_TABLE.OUTPUT_FORMAT
|
||||
- Tag names.
|
||||
|
||||
**Choices**:
|
||||
|
||||
|
||||
|
||||
- console **← (default)**
|
||||
|
||||
- github
|
||||
|
||||
- asciidoc
|
||||
|
||||
- html
|
||||
|
||||
- rst
|
||||
|
||||
* - **table.header**
|
||||
|
||||
`boolean <https://rougail.readthedocs.io/en/latest/variable.html#variables-types>`__ `mandatory`
|
||||
|
||||
**Command line**:
|
||||
|
||||
|
||||
|
||||
- --table.header
|
||||
|
||||
- --table.no-header
|
||||
|
||||
|
||||
|
||||
**Environment variable**: ROUGAILCLI_TABLE.HEADER
|
||||
- Add header in table.
|
||||
|
||||
**Default**: true
|
||||
22
docs/readme.txt
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
Building the doc locally
|
||||
============================
|
||||
|
||||
install
|
||||
---------
|
||||
|
||||
First, install a python virtual environment::
|
||||
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate
|
||||
|
||||
Then install the sphinx libraries::
|
||||
|
||||
pip install -r requirements.txt
|
||||
|
||||
The generatef html output is located in the `docs/build/html` subfolder,
|
||||
you can modify the target or the output type in the :file:`docs/Makefile`.
|
||||
|
||||
scraps
|
||||
---------
|
||||
|
||||
`variable <https://en.wikipedia.org/wiki/Variable_(computer_science)>`_
|
||||
215
docs/release.rst
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
Release procedure
|
||||
=================
|
||||
|
||||
We are using Comitizen.
|
||||
|
||||
We are automating vi semantic versionning (SemVer) + CHANGELOG with Commitizen
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
With each release, a single command (``cz bump --changelog``) will
|
||||
automatically:
|
||||
|
||||
- Analyze your commits (Conventional Commits)
|
||||
- Calculate the new version (patch, minor, major)
|
||||
- Update the version in your files
|
||||
- Generate/update the CHANGELOG.md - Create the release commit and Git tag
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
.. code:: bash
|
||||
|
||||
# Global installation or within your virtual environment
|
||||
pip install commitizen
|
||||
|
||||
# Verify installation
|
||||
cz version
|
||||
|
||||
Working with Conventional Commits
|
||||
---------------------------------
|
||||
|
||||
Creating standardized commits
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Two methods:
|
||||
|
||||
**Method 1: Interactive guide (recommended for beginners)**
|
||||
|
||||
.. code:: bash
|
||||
|
||||
cz commit
|
||||
|
||||
An assistant guides you step by step: 1. Choose the change type
|
||||
(``fix``, ``feat``, ``docs``, etc.) 2. Enter the message 3. Describe the
|
||||
scope (optional) 4. Indicate breaking changes (if any)
|
||||
|
||||
**Method 2: Manually**
|
||||
|
||||
.. code:: bash
|
||||
|
||||
# Bug fix → patch (0.1.0 → 0.1.1)
|
||||
git commit -m "fix: fix connection timeout"
|
||||
|
||||
# New feature → minor (0.1.0 → 0.2.0)
|
||||
git commit -m "feat: add OAuth2 authentication"
|
||||
|
||||
# Breaking change → major (0.1.0 → 1.0.0)
|
||||
git commit -m "feat: new REST API
|
||||
|
||||
BREAKING CHANGE: removed v1 endpoints"
|
||||
|
||||
Commit types and version impact
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
+-----------------------+-----------------------+-----------------------+
|
||||
| Commit type | Incrementation | Example |
|
||||
+=======================+=======================+=======================+
|
||||
| ``fix:`` | **patch** (+0.0.1) | ``f |
|
||||
| | | ix: fix display bug`` |
|
||||
+-----------------------+-----------------------+-----------------------+
|
||||
| ``perf:`` | **patch** (+0.0.1) | ``per |
|
||||
| | | f: optimize queries`` |
|
||||
+-----------------------+-----------------------+-----------------------+
|
||||
| ``feat:`` | **minor** (+0.1.0) | ``f |
|
||||
| | | eat: add PDF export`` |
|
||||
+-----------------------+-----------------------+-----------------------+
|
||||
| ``BREAKING CHANGE:`` | **major** (+1.0.0) | any type + |
|
||||
| (in message) | | ``BREAKING CHANGE:`` |
|
||||
+-----------------------+-----------------------+-----------------------+
|
||||
|
||||
--------------
|
||||
|
||||
The magic command - Creating a release
|
||||
--------------------------------------
|
||||
|
||||
When you’re ready to publish a new version:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
# Analyzes commits since last tag and executes the release
|
||||
cz bump --changelog
|
||||
|
||||
What this command does exactly:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
1. **Analyzes** all commits since the last Git tag
|
||||
2. **Calculates** the next version (patch/minor/major)
|
||||
3. **Updates** the version in all listed files
|
||||
4. **Generates/updates** the ``CHANGELOG.md`` (adds the new entry at the
|
||||
top)
|
||||
5. **Automatically commits** the changes with the message:
|
||||
``"bump: version X.Y.Z"``
|
||||
6. **Creates a Git tag** (format ``vX.Y.Z``)
|
||||
|
||||
Concrete execution example:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: bash
|
||||
|
||||
$ cz bump --changelog
|
||||
INFO: Starting version bump from 1.0.0 to 1.1.0
|
||||
INFO: Updating version in pyproject.toml
|
||||
INFO: Updating version in src/my_project/__init__.py
|
||||
INFO: Generating CHANGELOG.md
|
||||
INFO: Created commit: bump: version 1.1.0
|
||||
INFO: Created tag: v1.1.0
|
||||
|
||||
--------------
|
||||
|
||||
Managing the auto-generated CHANGELOG
|
||||
-------------------------------------
|
||||
|
||||
The ``CHANGELOG.md`` file will look like this:
|
||||
|
||||
.. code:: markdown
|
||||
|
||||
## v1.1.0 (2024-01-15)
|
||||
|
||||
### Feat
|
||||
|
||||
- add OAuth2 authentication
|
||||
- add PDF export
|
||||
|
||||
### Fix
|
||||
|
||||
- fix connection timeout
|
||||
|
||||
## v1.0.0 (2024-01-10)
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- removed v1 endpoints
|
||||
|
||||
### Feat
|
||||
|
||||
- first version of REST API
|
||||
|
||||
**You can customize the template** by adding to ``pyproject.toml``:
|
||||
|
||||
.. code:: toml
|
||||
|
||||
[tool.commitizen]
|
||||
# ... existing configuration ...
|
||||
changelog_template = "custom_changelog_template.j2" # Custom Jinja2 template
|
||||
|
||||
--------------
|
||||
|
||||
Pushing the release to Git
|
||||
--------------------------
|
||||
|
||||
After ``cz bump --changelog``, you have a commit and a tag locally. Push
|
||||
them:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
# Push the commit and tags
|
||||
git push --follow-tags
|
||||
|
||||
--------------
|
||||
|
||||
Useful daily commands
|
||||
---------------------
|
||||
|
||||
+-----------------------------------+-----------------------------------+
|
||||
| Command | Purpose |
|
||||
+===================================+===================================+
|
||||
| ``cz commit`` | Interactive guide to create a |
|
||||
| | conventional commit |
|
||||
+-----------------------------------+-----------------------------------+
|
||||
| ``cz bump --changelog`` | **The main command**: bumps |
|
||||
| | version + CHANGELOG |
|
||||
+-----------------------------------+-----------------------------------+
|
||||
| ``cz check`` | Checks if your last commit |
|
||||
| | follows the convention |
|
||||
+-----------------------------------+-----------------------------------+
|
||||
| ``cz version`` | Displays current version |
|
||||
| | (according to Commitizen) |
|
||||
+-----------------------------------+-----------------------------------+
|
||||
| ``cz changelog`` | Generates only the CHANGELOG |
|
||||
| | without bumping |
|
||||
+-----------------------------------+-----------------------------------+
|
||||
| ``cz bump --prerelease alpha`` | Creates a pre-release version |
|
||||
| | (e.g., 1.0.0-alpha.1) |
|
||||
+-----------------------------------+-----------------------------------+
|
||||
|
||||
--------------
|
||||
|
||||
Summary: The ideal workflow in 3 steps
|
||||
--------------------------------------
|
||||
|
||||
.. code:: bash
|
||||
|
||||
# 1. During development: standardized commits
|
||||
git add .
|
||||
cz commit # or git commit -m "feat: ..."
|
||||
|
||||
# 2. When you're ready for a release
|
||||
cz bump --changelog
|
||||
|
||||
# 3. Push to Git
|
||||
git push --follow-tags
|
||||
|
||||
**And that’s it!** Version bumped, CHANGELOG generated, tag created, all
|
||||
automated.
|
||||
|
|
@ -1,81 +1,3 @@
|
|||
alabaster==0.7.13
|
||||
asttokens==2.4.1
|
||||
attrs==23.1.0
|
||||
Babel==2.13.1
|
||||
certifi==2023.7.22
|
||||
charset-normalizer==3.3.2
|
||||
click==8.1.7
|
||||
colorama==0.4.6
|
||||
comm==0.2.0
|
||||
debugpy==1.8.0
|
||||
decorator==5.1.1
|
||||
docutils==0.18.1
|
||||
exceptiongroup==1.1.3
|
||||
executing==2.0.1
|
||||
fastjsonschema==2.18.1
|
||||
greenlet==3.0.1
|
||||
idna==3.4
|
||||
imagesize==1.4.1
|
||||
importlib-metadata==6.8.0
|
||||
ipykernel==6.26.0
|
||||
ipython==8.17.2
|
||||
jedi==0.19.1
|
||||
Jinja2==3.1.2
|
||||
jsonschema==4.19.2
|
||||
jsonschema-specifications==2023.7.1
|
||||
jupyter-cache==1.0.0
|
||||
jupyter_client==8.6.0
|
||||
jupyter_core==5.5.0
|
||||
livereload==2.6.3
|
||||
markdown-it-py==3.0.0
|
||||
MarkupSafe==2.1.3
|
||||
matplotlib-inline==0.1.6
|
||||
mdit-py-plugins==0.4.0
|
||||
mdurl==0.1.2
|
||||
myst-nb==1.0.0
|
||||
myst-parser==2.0.0
|
||||
nbclient==0.9.0
|
||||
nbformat==5.9.2
|
||||
nest-asyncio==1.5.8
|
||||
packaging==23.2
|
||||
parso==0.8.3
|
||||
pexpect==4.8.0
|
||||
platformdirs==4.0.0
|
||||
prompt-toolkit==3.0.40
|
||||
psutil==5.9.6
|
||||
ptyprocess==0.7.0
|
||||
pure-eval==0.2.2
|
||||
Pygments==2.16.1
|
||||
python-dateutil==2.8.2
|
||||
PyYAML==6.0.1
|
||||
pyzmq==25.1.1
|
||||
referencing==0.30.2
|
||||
requests==2.31.0
|
||||
rpds-py==0.12.0
|
||||
six==1.16.0
|
||||
snowballstemmer==2.2.0
|
||||
Sphinx==7.2.6
|
||||
sphinx-autobuild==2021.3.14
|
||||
sphinx-copybutton==0.5.2
|
||||
sphinx-lesson==0.8.15
|
||||
sphinx-minipres==0.2.1
|
||||
sphinx-rtd-theme==1.3.0
|
||||
sphinx-rtd-theme-ext-color-contrast==0.3.1
|
||||
sphinx-tabs==3.4.4
|
||||
sphinx-togglebutton==0.3.2
|
||||
sphinxcontrib-applehelp==1.0.7
|
||||
sphinxcontrib-devhelp==1.0.5
|
||||
sphinxcontrib-htmlhelp==2.0.4
|
||||
sphinxcontrib-jquery==4.1
|
||||
sphinxcontrib-jsmath==1.0.1
|
||||
sphinxcontrib-qthelp==1.0.6
|
||||
sphinxcontrib-serializinghtml==1.1.9
|
||||
SQLAlchemy==2.0.23
|
||||
stack-data==0.6.3
|
||||
tabulate==0.9.0
|
||||
tornado==6.3.3
|
||||
traitlets==5.13.0
|
||||
typing_extensions==4.8.0
|
||||
urllib3==2.0.7
|
||||
wcwidth==0.2.9
|
||||
zipp==3.17.0
|
||||
sphinx
|
||||
sphinx-lesson
|
||||
sphinxnotes-strike
|
||||
|
|
|
|||
77
docs/rw_ro_modes.rst
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
:orphan:
|
||||
|
||||
Read-write or read-only modes
|
||||
==================================
|
||||
|
||||
The read-write mode
|
||||
--------------------
|
||||
|
||||
When you are in the design phase, your are designing the structure file or
|
||||
setting values is some user data files, you have the role of :term:`integrator`
|
||||
or :term:`operator`. Then you need to have access to all the data, even
|
||||
those which are :term:`hidden` or :term:`disabled`\ .
|
||||
|
||||
In this phase, the configuration shall be in `RW` mode.
|
||||
|
||||
|
||||
.. glossary::
|
||||
|
||||
read-write
|
||||
|
||||
In the read-write mode (RW mode), all settings are accessible and can
|
||||
be modified. For example, a variable which has the `frozen` property
|
||||
can be modified. A `hidden` or `disabled` variable is accessible.
|
||||
|
||||
We are in the rôle of an :term:`integrator` or an :term:`operator`.
|
||||
We are therefore in a situation where we are **using** this configuration.
|
||||
|
||||
The read-only mode
|
||||
--------------------
|
||||
|
||||
Once the configuration has beed designed, it is used.
|
||||
The situation is different. The configuration behaves as a system.
|
||||
|
||||
.. glossary::
|
||||
|
||||
read-only
|
||||
|
||||
In the read-only mode (RO mode), the configuration cannot be modified.
|
||||
We are **using** a configuration.
|
||||
|
||||
In the usage mode, we are therefore in a situation where the configuration
|
||||
cannot be changed. The configuration's data are immutable.
|
||||
|
||||
|
||||
RO or RW mode?
|
||||
---------------
|
||||
|
||||
Here is an image which summarizes these explanations:
|
||||
|
||||
.. image:: images/read_write.png
|
||||
|
||||
|
||||
How to enable
|
||||
|
||||
By default in `rougail-cli`, the `RO` mode is activated.
|
||||
|
||||
If you need to enable the `RW` mode, there is an `rougail-cli` option:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
env ROUGAIL_MANUAL.USE_FOR_HTTPS=true rougail -m structfile/proxy2.yml -u yaml environment --yaml.filename userdata/proxy.yml -o json --json.read_write
|
||||
|
||||
The output is:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"manual": {
|
||||
"http_proxy": {
|
||||
"address": "toto.fr",
|
||||
"port": "8888"
|
||||
},
|
||||
"use_for_https": true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
86
docs/structured_data/data_integrity.rst
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
Data integrity
|
||||
===============
|
||||
|
||||
Data integrity refers to the fact that data must be reliable and accurate throughout its lifecycle.
|
||||
|
||||
This means that the value must be:
|
||||
|
||||
- of high quality
|
||||
- appropriate to the overall context
|
||||
|
||||
Isolated variable
|
||||
-----------------
|
||||
|
||||
.. _data_quality:
|
||||
|
||||
Data quality
|
||||
~~~~~~~~~~~~
|
||||
|
||||
The values of the variables must be individually of good quality.
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
|
||||
typing
|
||||
variable_validation
|
||||
|
||||
.. _access_control:
|
||||
|
||||
Access control
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
|
||||
mode
|
||||
variable_properties
|
||||
|
||||
.. _overall_coherence:
|
||||
|
||||
Overall coherence
|
||||
-----------------
|
||||
|
||||
.. glossary::
|
||||
|
||||
conherence
|
||||
|
||||
An isolated variable can be considered to be of quality
|
||||
but become inconsistent depending on the context.
|
||||
|
||||
Overall coherence is initially managed by personalized validators
|
||||
which will validate the value of a variable in relation to others.
|
||||
But it also depends on the availability of the variable depending on the context.
|
||||
|
||||
.. _consistency:
|
||||
|
||||
Consistency
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. glossary::
|
||||
|
||||
consistency
|
||||
|
||||
Consistency is validating the value of a variable in relation to other
|
||||
variables in the :term:`context`.
|
||||
This does not only concern the variables themselves, such as their type.
|
||||
Of course there is a typed base validation.
|
||||
|
||||
The aim is to validate a variable in a :term:`configuration`,
|
||||
the :term:`structured data` and the :term:`user data` based on the situation.
|
||||
|
||||
This is what we call a "context"—meaning the dataset to which a variable is linked.
|
||||
|
||||
For example, if a minimum value and then a maximum value are requested,
|
||||
the minimum must be lesser than the maximum. This is not type consistency,
|
||||
but this is yet consistency.
|
||||
|
||||
Context access control
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Access control occurs as soon as an attempt is made to access a variable.
|
||||
|
||||
Remember, we talked about the :ref:`hidden variable <hidden>` and :ref:`disabled variable <disabled>` variables.
|
||||
|
||||
These properties become fully meaningful when managing overall consistency.
|
||||
|
||||
Why ask for the domain name of a service if we haven't activated that service just before?
|
||||
71
docs/structured_data/documentation.rst
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
.. _data_documentation:
|
||||
|
||||
Data documentation
|
||||
==================
|
||||
|
||||
Documentation is an integral part of the definition of :term:`structured data`.
|
||||
|
||||
In a sense, we talk about :term:`structured data` and not `schema` in Rougail because the documentation is an full part of the variable definition.
|
||||
|
||||
More broadly, considering the use of a :term:`VaC` tool has the advantage of eliminating the need to manage documentation oneself.
|
||||
|
||||
A lot of useful information for the :term:`operator` is naturally present when defining our variables. I'm thinking of its type, the constraints applied, its default value, the mode level, etc.
|
||||
|
||||
But it is still necessary, as an :term:`integrator`, to guide the :term:`operator`.
|
||||
|
||||
Describe the variable
|
||||
---------------------
|
||||
|
||||
Describing the variable you create is not mandatory but it is highly recommended.
|
||||
Even a very well-chosen variable name does not replace a description.
|
||||
|
||||
.. glossary::
|
||||
|
||||
description
|
||||
|
||||
A description allows you to describe the expected value(s) of a variable concisely and clearly.
|
||||
It is designed to be clear precise and short.
|
||||
|
||||
The description is used in different places in Rougail.
|
||||
|
||||
Examples include:
|
||||
|
||||
- warning/error message
|
||||
- different output
|
||||
|
||||
Additional help to understand the variable
|
||||
------------------------------------------
|
||||
|
||||
Help is a property that only concerns documentation.
|
||||
|
||||
.. glossary::
|
||||
|
||||
help
|
||||
|
||||
A help helps to clarify any ambiguity about the variable’s purpose.
|
||||
It can be long and detailed.
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`help <../tutorial/document>`
|
||||
|
||||
Give examples of possible value
|
||||
-------------------------------
|
||||
|
||||
Often a good example is more effective than a long text.
|
||||
|
||||
Don't hesitate to guide the :term:`operator` with relevant examples.
|
||||
|
||||
Examples is a property that only concerns documentation.
|
||||
|
||||
.. seealso:: tutorial with a real world sample :doc:`examples <../tutorial/document>`
|
||||
|
||||
Specialized variables
|
||||
-----------------------
|
||||
|
||||
In a context of value presentation, :term:`tagging <tag>` can be very useful. The :term:`tags <tag>` allow you to display variable values without knowing the list of variable paths.
|
||||
|
||||
.. glossary::
|
||||
|
||||
tag
|
||||
|
||||
A tag is just a name.
|
||||
Adding a tag is a way to attach additional information or label to variables.
|
||||
BIN
docs/structured_data/images/schema.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
95
docs/structured_data/images/schema.svg
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg width="168.61894mm" height="47.245815mm" viewBox="0 0 168.61894 47.245817" version="1.1" id="svg1281" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs id="defs1278">
|
||||
<linearGradient y2="25.1" x2="86.82" y1="14.793" x1="98.330002" gradientTransform="matrix(0.25589145,0,0,0.25589145,-2.8433289,50.011843)" gradientUnits="userSpaceOnUse" id="I" xlink:href="#E"/>
|
||||
<linearGradient id="E">
|
||||
<stop id="Z"/>
|
||||
<stop offset="1" id="a" stop-color="#ddd" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="H" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,0.97467889,0,0.43910718)" cx="89.510002" cy="22.254" r="18.278999" xlink:href="#D"/>
|
||||
<linearGradient id="D">
|
||||
<stop id="X"/>
|
||||
<stop offset="1" id="Y" stop-opacity="0.536"/>
|
||||
</linearGradient>
|
||||
<filter id="F" x="-0.14513263" width="1.2902653" y="-0.17041424" height="1.3408285">
|
||||
<feGaussianBlur stdDeviation="1.81881" id="b"/>
|
||||
</filter>
|
||||
<radialGradient r="44.419998" cy="100.32" cx="81.790001" gradientTransform="matrix(0.52985595,-0.42254789,0.47025276,0.58967565,-76.841108,56.306453)" gradientUnits="userSpaceOnUse" id="J" xlink:href="#C"/>
|
||||
<linearGradient id="C">
|
||||
<stop id="V" stop-color="#eee"/>
|
||||
<stop offset="1" id="W" stop-color="#d2d2d2"/>
|
||||
</linearGradient>
|
||||
<filter id="G" x="-0.069831288" y="-0.052595388" width="1.1396626" height="1.1051908">
|
||||
<feGaussianBlur stdDeviation="2.58594" id="c"/>
|
||||
</filter>
|
||||
<radialGradient id="H-9" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,0.97467889,0,0.43910718)" cx="89.510002" cy="22.254" r="18.278999" xlink:href="#D"/>
|
||||
<filter id="F-4" x="-0.14513263" width="1.2902653" y="-0.17041424" height="1.3408285">
|
||||
<feGaussianBlur stdDeviation="1.81881" id="b-5"/>
|
||||
</filter>
|
||||
<radialGradient r="44.419998" cy="100.32" cx="81.790001" gradientTransform="matrix(0.52985595,-0.42254789,0.47025276,0.58967565,-72.984982,64.346506)" gradientUnits="userSpaceOnUse" id="J-2" xlink:href="#C"/>
|
||||
<filter id="G-7" x="-0.069831288" y="-0.052595388" width="1.1396626" height="1.1051908">
|
||||
<feGaussianBlur stdDeviation="2.58594" id="c-4"/>
|
||||
</filter>
|
||||
<linearGradient id="linearGradient34385" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.25589145,0,0,0.25589145,1.0127971,58.051896)" x1="98.330002" y1="14.793" x2="86.82" y2="25.1" xlink:href="#E"/>
|
||||
<marker style="overflow:visible" id="Arrow1Lstart-5-4-3" refX="0" refY="0" orient="auto">
|
||||
<path transform="matrix(0.8,0,0,0.8,10,0)" style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt" d="M 0,0 5,-5 -12.5,0 5,5 Z" id="path1593-62-0-2"/>
|
||||
</marker>
|
||||
<marker style="overflow:visible" id="Arrow1Lend-9-0-6" refX="0" refY="0" orient="auto">
|
||||
<path transform="matrix(-0.8,0,0,-0.8,-10,0)" style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt" d="M 0,0 5,-5 -12.5,0 5,5 Z" id="path1596-1-4-5"/>
|
||||
</marker>
|
||||
<marker style="overflow:visible" id="Arrow1Lstart-5-4-3-3" refX="0" refY="0" orient="auto">
|
||||
<path transform="matrix(0.8,0,0,0.8,10,0)" style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt" d="M 0,0 5,-5 -12.5,0 5,5 Z" id="path1593-62-0-2-6"/>
|
||||
</marker>
|
||||
<marker style="overflow:visible" id="Arrow1Lend-9-0-6-7" refX="0" refY="0" orient="auto">
|
||||
<path transform="matrix(-0.8,0,0,-0.8,-10,0)" style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt" d="M 0,0 5,-5 -12.5,0 5,5 Z" id="path1596-1-4-5-5"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<g id="layer1" transform="translate(3.2103291,-46.338646)">
|
||||
<rect style="fill:#ffffff;fill-rule:evenodd;stroke-width:0.269574;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;paint-order:fill markers stroke" id="rect71278" width="168.61894" height="47.245815" x="-3.2103291" y="46.338646"/>
|
||||
<path style="fill:#bdde8a;fill-opacity:1;stroke-width:0.118188" d="m 117.06678,89.005809 c 3.32888,-11.30488 0.19958,-23.55451 -9.48513,-31.49972 -12.918901,-10.5985 -31.983485,-8.71745 -42.581987,4.20144 -6.427917,7.83523 -8.193923,18.16264 -5.762537,27.25933 z" id="path1669"/>
|
||||
<path style="fill:#dd463a;fill-opacity:1;stroke-width:0.11835" d="m 90.779923,60.337869 c 0.635381,-0.77697 1.685125,-1.15419 2.71514,-0.87853 1.02741,0.27696 1.746939,1.12788 1.912761,2.11579 0.813014,-0.58438 1.924577,-0.678 2.847983,-0.14245 0.922106,0.53295 1.397104,1.54196 1.301016,2.53924 0.936647,-0.35483 2.035087,-0.15561 2.788897,0.60014 0.75251,0.75587 0.95106,1.85329 0.60122,2.7912 0.99586,-0.099 2.00483,0.37852 2.53763,1.30458 0.53279,0.92462 0.44202,2.03532 -0.13817,2.85187 0.98794,0.16354 1.83772,0.88517 2.11404,1.91799 0.27621,1.03153 -0.0987,2.08155 -0.86951,2.71867 0.91159,0.4142 1.54697,1.33231 1.54697,2.40212 l -19.750821,0.0185 c -0.08619,-8.87358 0.05469,-12.15623 0,-19.7864 1.064285,0 1.978475,0.63451 2.392844,1.54729 z" id="path8-7"/>
|
||||
<path style="fill:#dfdfdf;fill-opacity:1;stroke-width:0.118351" d="m 85.994239,60.337869 c -0.635381,-0.77697 -1.68513,-1.15419 -2.715141,-0.87853 -1.027412,0.27696 -1.746942,1.12788 -1.912762,2.11579 -0.813017,-0.58438 -1.924578,-0.678 -2.847983,-0.14245 -0.922107,0.53295 -1.397106,1.54196 -1.301018,2.53924 -0.936642,-0.35483 -2.035084,-0.15561 -2.78889,0.60014 -0.752505,0.75587 -0.951062,1.85329 -0.601224,2.7912 -0.995855,-0.099 -2.004829,0.37852 -2.537622,1.30458 -0.532793,0.92463 -0.442024,2.03532 0.138162,2.85187 -0.987936,0.16354 -1.83771,0.88517 -2.114034,1.91799 -0.276207,1.03153 0.09869,2.08155 0.869511,2.71867 -0.911587,0.4142 -1.546967,1.33231 -1.546967,2.40212 l 19.750808,0.0185 c 0.08619,-8.87358 -0.05468,-12.15623 0,-19.7864 -1.064285,0 -1.978473,0.63451 -2.39284,1.54729 z" id="path8-7-9"/>
|
||||
<path style="fill:#ad622f;fill-opacity:1;stroke-width:0.164269" d="m 105.37882,74.041619 c 0,1.54396 -1.20452,2.79588 -2.69038,2.79588 v -5.59159 c 1.48586,0 2.69038,1.25174 2.69038,2.79571 z" id="path18"/>
|
||||
<path style="fill:#80451d;fill-opacity:1;stroke-width:0.164269" d="m 99.998051,74.041619 c 0,1.54396 1.204519,2.79588 2.690389,2.79588 v -5.59159 c -1.48587,0 -2.690389,1.25174 -2.690389,2.79571 z" id="path18-5"/>
|
||||
<path style="fill:#ad622f;fill-opacity:1;stroke-width:0.164269" d="m 99.552793,68.283779 c 0,1.54397 -1.204516,2.79588 -2.690383,2.79588 v -5.59159 c 1.485867,0 2.690383,1.25175 2.690383,2.79571 z" id="path18-6"/>
|
||||
<path style="fill:#80451d;fill-opacity:1;stroke-width:0.164269" d="m 94.172031,68.283779 c 0,1.54397 1.204516,2.79588 2.690379,2.79588 v -5.59159 c -1.485863,0 -2.690379,1.25175 -2.690379,2.79571 z" id="path18-5-7"/>
|
||||
<path style="fill:#ad622f;fill-opacity:1;stroke-width:0.164269" d="m 95.834977,78.415739 c 0,1.54396 -1.204511,2.79588 -2.690379,2.79588 v -5.5916 c 1.485868,0 2.690379,1.25175 2.690379,2.79572 z" id="path18-3"/>
|
||||
<path style="fill:#80451d;fill-opacity:1;stroke-width:0.164269" d="m 90.454219,78.415739 c 0,1.54396 1.204516,2.79588 2.690379,2.79588 v -5.5916 c -1.485863,0 -2.690379,1.25175 -2.690379,2.79572 z" id="path18-5-5"/>
|
||||
<path style="fill:#115d69;fill-opacity:1;stroke-width:0.0869262" d="m 88.387079,78.576969 v 10.42881 l 17.878351,3e-5 c 3.409,-0.5815 2.48827,-9.74724 4.15092,-10.45655 z" id="path34-6"/>
|
||||
<path style="fill:#0f6d7c;fill-opacity:1;stroke-width:0.0869262" d="m 88.387079,78.576969 v 10.42881 l -17.878338,3e-5 c -3.40901,-0.5815 -2.488279,-9.74724 -4.150924,-10.45655 z" id="path34-6-56"/>
|
||||
<text style="font-size: 2.52546px; line-height: 1; font-family: sans-serif; letter-spacing: 0px; word-spacing: 0px; stroke-width: 0.631367; white-space: pre;" x="157.79997" y="67.333687" id="text18049"><tspan id="tspan18047" x="157.79997" y="67.333687" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.52546px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:center;text-anchor:middle;stroke-width:0.631367">I</tspan><tspan x="157.79997" y="69.859146" id="tspan18051" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.52546px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:center;text-anchor:middle;stroke-width:0.631367">R</tspan><tspan x="157.79997" y="72.384605" id="tspan21745" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.52546px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:center;text-anchor:middle;stroke-width:0.631367">A</tspan><tspan x="157.79997" y="74.910065" id="tspan21747" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.52546px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:center;text-anchor:middle;stroke-width:0.631367">M</tspan><tspan x="157.79997" y="77.435524" id="tspan21749" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.52546px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:center;text-anchor:middle;stroke-width:0.631367">I</tspan><tspan x="157.79997" y="79.960983" id="tspan21751" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.52546px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:center;text-anchor:middle;stroke-width:0.631367">S</tspan><tspan x="157.79997" y="82.48645" id="tspan21753" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.52546px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:center;text-anchor:middle;stroke-width:0.631367">U</tspan></text>
|
||||
<g id="g35021" transform="matrix(0.27056412,0,0,0.27056412,119.91122,50.33958)">
|
||||
<path style="fill:#2a80af;fill-opacity:1;stroke:#000000;stroke-width:1.16676;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="m 97.548571,30.277658 c 0,0 0,0 50.672369,0 1.88694,0.08961 2.56808,0.252436 3.63129,1.152545 0.75125,0.926179 0.92342,1.528485 1.03575,3.22047 l -6e-5,9.425084 c 0,0 0.0893,2.236438 -1.01074,3.336475 -1.10002,1.10004 -1.70636,1.255327 -3.65624,1.330563 h -8.55935 V 39.35038 H 97.548571 Z" id="path6247"/>
|
||||
<circle style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.16676;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:7.7;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke" id="path4757" cx="146.08244" cy="39.510098" r="2.285794"/>
|
||||
<path style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.16676;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="m 139.66159,48.742796 c 0,0 0,0 -50.67237,0 -1.88694,-0.08961 -2.56808,-0.252436 -3.63129,-1.152545 -0.75125,-0.926179 -0.92342,-1.528485 -1.03575,-3.22047 l 6e-5,-9.425084 c 0,0 -0.0893,-2.236438 1.01074,-3.336475 1.10002,-1.10004 1.70636,-1.255327 3.65624,-1.330563 h 8.55935 v 9.392415 h 42.11302 z" id="path6247-92"/>
|
||||
<circle style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.16676;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:7.7;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke" id="path4757-0" cx="-91.127716" cy="-39.510357" r="2.285794" transform="scale(-1)"/>
|
||||
</g>
|
||||
<g id="g35021-2" transform="matrix(0,-0.27056412,0.27056412,0,141.59837,106.23691)">
|
||||
<path style="fill:#2a80af;fill-opacity:1;stroke:#000000;stroke-width:1.16676;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="m 97.548571,30.277658 c 0,0 0,0 50.672369,0 1.88694,0.08961 2.56808,0.252436 3.63129,1.152545 0.75125,0.926179 0.92342,1.528485 1.03575,3.22047 l -6e-5,9.425084 c 0,0 0.0893,2.236438 -1.01074,3.336475 -1.10002,1.10004 -1.70636,1.255327 -3.65624,1.330563 h -8.55935 V 39.35038 H 97.548571 Z" id="path6247-3"/>
|
||||
<circle style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.16676;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:7.7;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke" id="path4757-75" cx="146.08244" cy="39.510098" r="2.285794"/>
|
||||
<path style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.16676;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="m 139.66159,48.742796 c 0,0 0,0 -50.67237,0 -1.88694,-0.08961 -2.56808,-0.252436 -3.63129,-1.152545 -0.75125,-0.926179 -0.92342,-1.528485 -1.03575,-3.22047 l 6e-5,-9.425084 c 0,0 -0.0893,-2.236438 1.01074,-3.336475 1.10002,-1.10004 1.70636,-1.255327 3.65624,-1.330563 h 8.55935 v 9.392415 h 42.11302 z" id="path6247-92-9"/>
|
||||
<circle style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.16676;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:7.7;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke" id="path4757-0-2" cx="-91.127716" cy="-39.510357" r="2.285794" transform="scale(-1)"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#Arrow1Lstart-5-4-3);marker-mid:url(#Arrow1Lend-9-0-6)" d="m 144.32503,72.904584 -24.95942,0.274769" id="path1591-36-6-2"/>
|
||||
<path style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#Arrow1Lstart-5-4-3-3);marker-mid:url(#Arrow1Lend-9-0-6-7)" d="M 57.31659,73.224942 32.357284,73.499711" id="path1591-36-6-2-3"/>
|
||||
<g id="g44" transform="matrix(0.00210332,0,0,0.00210332,64.449231,202.96893)" style="fill-rule:evenodd;stroke-width:28.222;stroke-linejoin:round">
|
||||
<g id="id2" class="Master_Slide">
|
||||
<g id="bg-id2" class="Background"/>
|
||||
<g id="bo-id2" class="BackgroundObjects"/>
|
||||
</g>
|
||||
</g>
|
||||
<path d="M 20.09375,4.1185004 V 122.1185 H 108.9375 V 35.96225 l -0.59375,-0.625 c 0.21045,0.144391 0.41688,0.302162 0.625,0.4375 L 78.09375,4.1497504 c 0.05654,0.079597 0.09993,0.1703021 0.15625,0.25 L 78,4.1185004 Z" id="1" transform="matrix(0.25589145,0,0,0.2569796,-2.8433289,49.872213)" opacity="0.809" filter="url(#G)"/>
|
||||
<path d="m 2.3024891,50.707553 v 30.19519 H 25.036843 v -22.04665 l -7.91664,-8.14854 z" id="2" fill="url(#J)" style="fill:url(#J);stroke-width:0.264583"/>
|
||||
<text x="-4.7298937" y="51.798679" id="7" fill="#555555" font-family="'Jigsaw Trouserdrop'" text-anchor="middle" text-align="center" line-height="125%" font-size="40px" style="font-size: 0.705556px; stroke-width: 0.264583; white-space: pre;"><tspan id="tspan23309" x="4.2476912" y="51.798679" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583"><tspan id="K" x="4.2476912" y="51.798679" font-family="'Liberation Sans'" text-align="center" line-height="125%" font-weight="bold" font-size="18px" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.0700043">version: '0.10'</tspan></tspan><tspan id="tspan23311" x="4.2476912" y="52.680626" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583"/><tspan x="4.2476912" y="53.562569" id="tspan23313" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583"># describe a first service with a single file</tspan><tspan x="4.2476912" y="54.444515" id="tspan23315" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">services:</tspan><tspan x="4.2476912" y="55.326458" id="tspan23317" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">- service:</tspan><tspan x="4.2476912" y="56.208405" id="tspan23319" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">- name: my_service</tspan><tspan x="4.2476912" y="57.090347" id="tspan23321" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">file:</tspan><tspan x="4.2476912" y="57.972294" id="tspan23323" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">- engine: jinja</tspan><tspan x="4.2476912" y="58.85424" id="tspan23325" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">text: /etc/filename</tspan><tspan x="4.2476912" y="59.736183" id="tspan23327" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583"/><tspan x="4.2476912" y="60.61813" id="tspan23329" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583"># describe a variable my_first_variable</tspan><tspan x="4.2476912" y="61.500072" id="tspan23331" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583"># and a family with a variable my_second_variable</tspan><tspan x="4.2476912" y="62.382019" id="tspan23333" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">variables:</tspan><tspan x="4.2476912" y="63.263966" id="tspan23335" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">- variable:</tspan><tspan x="4.2476912" y="64.145912" id="tspan23337" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">- name: my_first_variable</tspan><tspan x="4.2476912" y="65.027855" id="tspan23339" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">value:</tspan><tspan x="4.2476912" y="65.909798" id="tspan23341" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">- text: my_value</tspan><tspan x="4.2476912" y="66.79174" id="tspan23343" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">- family:</tspan><tspan x="4.2476912" y="67.673691" id="tspan23345" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">- name: my_family</tspan><tspan x="4.2476912" y="68.555634" id="tspan23347" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">variables:</tspan><tspan x="4.2476912" y="69.437576" id="tspan23349" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">- variable:</tspan><tspan x="4.2476912" y="70.319527" id="tspan23351" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">- name: my_second_variable</tspan><tspan x="4.2476912" y="71.201469" id="tspan23353" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">type: number</tspan><tspan x="4.2476912" y="72.083412" id="tspan23355" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">mandatory: true</tspan><tspan x="4.2476912" y="72.965355" id="tspan23357" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">value:</tspan><tspan x="4.2476912" y="73.847305" id="tspan23359" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">- text: 1</tspan><tspan x="4.2476912" y="74.729248" id="tspan23361" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583"/></text>
|
||||
<path id="4" d="m 81.698039,28.309502 0.135161,-8.351 C 81.901124,13.359407 80.956142,8.4107397 77.785779,3.9471419 L 80.362343,3.9159389 107.86271,29.53084 c -4.06802,-2.645393 -9.621189,-0.791242 -16.861906,-1.025606 z" transform="matrix(0.26883915,0,0,0.29428043,-4.2670299,49.943473)" opacity="0.505" fill="url(#H)" filter="url(#F)" style="fill:url(#H)"/>
|
||||
<path d="m 18.630159,56.864153 0.03459,-2.13695 c 0.01738,-1.68865 -0.712146,-2.86704 -1.523415,-4.00924 l 7.902242,8.09312 c -1.040972,-0.67693 -2.180077,-1.83687 -4.032915,-1.89684 z" id="5" fill="#eeeeee" style="stroke-width:0.264583"/>
|
||||
<path id="6" d="m 18.630159,56.864153 0.03459,-2.13695 c 0.01738,-1.68865 -0.712146,-2.86704 -1.523415,-4.00924 l 7.902242,8.09312 c -1.040972,-0.67693 -2.180077,-1.83687 -4.032915,-1.89684 z" fill="url(#I)" style="fill:url(#I);stroke-width:0.264583"/>
|
||||
<path d="M 20.09375,4.1185004 V 122.1185 H 108.9375 V 35.96225 l -0.59375,-0.625 c 0.21045,0.144391 0.41688,0.302162 0.625,0.4375 L 78.09375,4.1497504 c 0.05654,0.079597 0.09993,0.1703021 0.15625,0.25 L 78,4.1185004 Z" id="1-4" transform="matrix(0.25589145,0,0,0.2569796,1.0127971,57.912266)" opacity="0.809" filter="url(#G)" style="filter:url(#G-7)"/>
|
||||
<path d="m 6.1586151,58.747606 v 30.19519 H 28.892969 v -22.04665 l -7.91664,-8.14854 z" id="2-3" fill="url(#J)" style="fill:url(#J-2);stroke-width:0.264583"/>
|
||||
<text x="-0.87376881" y="59.83873" id="7-0" fill="#555555" font-family="'Jigsaw Trouserdrop'" text-anchor="middle" text-align="center" line-height="125%" font-size="40px" style="font-size: 0.705556px; stroke-width: 0.264583; white-space: pre;"><tspan id="tspan23309-7" x="8.103816" y="59.83873" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583"><tspan id="K-8" x="8.103816" y="59.83873" font-family="'Liberation Sans'" text-align="center" line-height="125%" font-weight="bold" font-size="18px" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.0700043">version: '0.10'</tspan></tspan><tspan id="tspan23311-6" x="8.103816" y="60.720676" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583"/><tspan x="8.103816" y="61.602619" id="tspan23313-8" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583"># describe a first service with a single file</tspan><tspan x="8.103816" y="62.484566" id="tspan23315-8" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">services:</tspan><tspan x="8.103816" y="63.366508" id="tspan23317-4" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">- service:</tspan><tspan x="8.103816" y="64.248451" id="tspan23319-3" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">- name: my_service</tspan><tspan x="8.103816" y="65.130402" id="tspan23321-1" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">file:</tspan><tspan x="8.103816" y="66.012344" id="tspan23323-4" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">- engine: jinja</tspan><tspan x="8.103816" y="66.894287" id="tspan23325-9" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">text: /etc/filename</tspan><tspan x="8.103816" y="67.776237" id="tspan23327-2" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583"/><tspan x="8.103816" y="68.65818" id="tspan23329-0" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583"># describe a variable my_first_variable</tspan><tspan x="8.103816" y="69.540123" id="tspan23331-6" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583"># and a family with a variable my_second_variable</tspan><tspan x="8.103816" y="70.422066" id="tspan23333-8" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">variables:</tspan><tspan x="8.103816" y="71.304016" id="tspan23335-9" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">- variable:</tspan><tspan x="8.103816" y="72.185959" id="tspan23337-2" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">- name: my_first_variable</tspan><tspan x="8.103816" y="73.067902" id="tspan23339-6" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">value:</tspan><tspan x="8.103816" y="73.949852" id="tspan23341-6" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">- text: my_value</tspan><tspan x="8.103816" y="74.831795" id="tspan23343-4" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">- family:</tspan><tspan x="8.103816" y="75.713737" id="tspan23345-9" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">- name: my_family</tspan><tspan x="8.103816" y="76.595688" id="tspan23347-5" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">variables:</tspan><tspan x="8.103816" y="77.477631" id="tspan23349-0" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">- variable:</tspan><tspan x="8.103816" y="78.359573" id="tspan23351-4" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">- name: my_second_variable</tspan><tspan x="8.103816" y="79.241516" id="tspan23353-8" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">type: number</tspan><tspan x="8.103816" y="80.123466" id="tspan23355-7" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">mandatory: true</tspan><tspan x="8.103816" y="81.005409" id="tspan23357-1" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">value:</tspan><tspan x="8.103816" y="81.887352" id="tspan23359-7" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583">- text: 1</tspan><tspan x="8.103816" y="82.769302" id="tspan23361-2" style="font-size:0.705556px;text-align:start;text-anchor:start;stroke-width:0.264583"/></text>
|
||||
<text x="17.430365" y="86.324524" id="7-7-7" fill="#555555" font-family="'Jigsaw Trouserdrop'" text-anchor="middle" text-align="center" line-height="125%" font-size="40px" style="font-size: 3.52777px; stroke-width: 0.264583; white-space: pre;"><tspan id="K-6-2" x="17.430365" y="86.324524" font-family="'Liberation Sans'" text-align="center" line-height="125%" font-weight="bold" font-size="18px" style="font-size:3.52777px;stroke-width:0.0700043">Structure file</tspan></text>
|
||||
<path id="4-2" d="m 81.698039,28.309502 0.135161,-8.351 C 81.901124,13.359407 80.956142,8.4107397 77.785779,3.9471419 L 80.362343,3.9159389 107.86271,29.53084 c -4.06802,-2.645393 -9.621189,-0.791242 -16.861906,-1.025606 z" transform="matrix(0.26883915,0,0,0.29428043,-0.41090387,57.983526)" opacity="0.505" fill="url(#H)" filter="url(#F)" style="fill:url(#H-9);filter:url(#F-4)"/>
|
||||
<path d="m 22.486285,64.904206 0.03459,-2.13695 c 0.01738,-1.68865 -0.712146,-2.86704 -1.523415,-4.00924 l 7.902242,8.09312 c -1.040972,-0.67693 -2.180077,-1.83687 -4.032915,-1.89684 z" id="5-6" fill="#eeeeee" style="stroke-width:0.264583"/>
|
||||
<path id="6-1" d="m 22.486285,64.904206 0.03459,-2.13695 c 0.01738,-1.68865 -0.712146,-2.86704 -1.523415,-4.00924 l 7.902242,8.09312 c -1.040972,-0.67693 -2.180077,-1.83687 -4.032915,-1.89684 z" fill="url(#I)" style="fill:url(#linearGradient34385);stroke-width:0.264583"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 26 KiB |
10
docs/structured_data/index.rst
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
The structure file and data
|
||||
============================
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
:caption: Rougail format's integrity and documentation
|
||||
|
||||
structured_data
|
||||
documentation
|
||||
data_integrity
|
||||
17
docs/structured_data/mode.rst
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
Mode
|
||||
====
|
||||
|
||||
.. index:: mode
|
||||
|
||||
By default, the mode is not configured. It is an optional feature.
|
||||
|
||||
Let's start by defining what we want to do with the modes.
|
||||
|
||||
We'll present a common example, but you'll need to define your own modes according to your needs.
|
||||
|
||||
Here is our classic use case of mode definition. We'll use three modes:
|
||||
|
||||
- `basic`: automatically sets mandatory variables without default values (in this case, the actor adapting the configuration will have to enter values) and manually sets variables that the actor defining the variables deems necessary.
|
||||
- `standard`: automatically sets all other variables
|
||||
- `advanced`: sets variables that the actor defining the variables decides to include. These variables are intended for a knowledgeable audience who know what to do.
|
||||
|
||||
194
docs/structured_data/structured_data.rst
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
The structure file
|
||||
=======================
|
||||
|
||||
What contains exactly a :term:`structure file`?
|
||||
-------------------------------------------------
|
||||
|
||||
.. glossary::
|
||||
|
||||
structure file
|
||||
|
||||
A structure file in the Rougail meaning is a YAML file that describes variables
|
||||
and their dependencies.
|
||||
There can be a lot of structure files located in many different folders.
|
||||
|
||||
Rougail reads all the structure files and loads them into a single object
|
||||
that represents the whole :term:`context`.
|
||||
|
||||
A :term:`structure file` is a YAML file whose structure is described in this documentation page.
|
||||
|
||||
A structure file contains a set of variables, usable in your application, for example in a template
|
||||
to generate configuration files.
|
||||
|
||||
:term:`Families <family>` and :term:`variables <variable>` can be defined in several structure files. These structure files are then aggregated.
|
||||
|
||||
File naming convention
|
||||
--------------------------
|
||||
|
||||
.. _filenamingconvention:
|
||||
|
||||
The structure files in a given folder
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
For the sake of clarity, we put the structured data in separate files.
|
||||
It's a good way to organize your rougail structures this way,
|
||||
in the real world we need separate files for different topics.
|
||||
|
||||
For example some files like this:
|
||||
|
||||
A file named :file:`firefox/00-proxy.yml` structure file and file named :file:`firefox/10-manual.yml`
|
||||
|
||||
::
|
||||
|
||||
.
|
||||
└── firefox
|
||||
├── 00-proxy.yml
|
||||
└── 10-manual.yml
|
||||
|
||||
.. note:: We of course could have put everything in one file.
|
||||
Again, it is better to separate the structures in different files
|
||||
for reasons of ordering and clarity.
|
||||
|
||||
Ordering your structure files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The order in which files are loaded is important in Rougail.
|
||||
In a given folder, files are loaded in alphabetical order.
|
||||
|
||||
Furthermore, for better readability of the order in which files are
|
||||
loaded into a folder, we have adopted a convention.
|
||||
To facilitate classification, we have defined a standard notation for structure file names:
|
||||
|
||||
::
|
||||
|
||||
XX-<name>.yml
|
||||
|
||||
Where `XX` is a two digits integer followed by an hyphen, and `<name>` is a name that describes
|
||||
the structure that is in this file. We advise you to adopt this convention as well.
|
||||
|
||||
File naming convention
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
There is no restriction to the `<name>` name part of file name. But it is preferable to only use
|
||||
lowercase ASCII letters, numbers and the `"_"` (undescore) character.
|
||||
|
||||
.. FIXME: et le moins "-" aussi non ?
|
||||
|
||||
.. _namespace:
|
||||
|
||||
Separation of structures into namespaces
|
||||
----------------------------------------
|
||||
|
||||
.. glossary::
|
||||
|
||||
namespace
|
||||
|
||||
A namespace is a way to organize and group related variables under a unique name.
|
||||
|
||||
It enables us to:
|
||||
|
||||
- avoid naming conflicts
|
||||
- permit logical grouping: related variables can be grouped together
|
||||
- scope control: namespaces limit the visibility of variable to the namespace itself
|
||||
|
||||
By default there is no namespace.
|
||||
|
||||
.. _defaultnamespace:
|
||||
|
||||
The default namespace
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The families and variables contained in these structure files are ordered, by default, in the `rougail` namespace. It is possible to change the name of this namespace with the :term:`variable namespace <variable_namespace>` parameter of the :doc:`configuration <configuration>`.
|
||||
|
||||
This namespace (the default namespace) is a bit special, it can access variables in another namespace.
|
||||
|
||||
The extra structure files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
An extra is a different namespace. The idea is to be able to classify the variables by theme.
|
||||
|
||||
Extra namespaces must be declared :doc:`when configuring Rougail <configuration>`.
|
||||
|
||||
In this namespace we cannot access variables from another `extra` namespace.
|
||||
On the other hand, it is possible to access the variable of the default namespace.
|
||||
|
||||
The header of a structure file
|
||||
-----------------------------------
|
||||
|
||||
A basic structure file is composed of:
|
||||
|
||||
- a YAML 1.2 standard header
|
||||
- a version attribute
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
...
|
||||
|
||||
The structure file processing
|
||||
----------------------------------
|
||||
|
||||
The :term:`structure files <structure file>` contain information that will be used by the consistency handling system for structure validation.
|
||||
This is what we call :term:`structured data` writen in :term:`Rougail format`.
|
||||
|
||||
.. figure:: images/schema.png
|
||||
:alt: The Rougail process
|
||||
:align: center
|
||||
|
||||
The Rougail process from structure files to :term:`Tiramisu` valition handler object
|
||||
|
||||
A variable-first DSL
|
||||
-----------------------
|
||||
|
||||
All of the declaring variables and writing consistency is as simple as writing YAML.
|
||||
|
||||
We can declare variables and describe the relationships between variables in a declarative style (that is, in a YAML file).
|
||||
|
||||
Once the structure files are loaded by Rougail, the :term:`Tiramisu` consistency management tool can check the consistency of the variables between them.
|
||||
|
||||
.. glossary::
|
||||
|
||||
DSL
|
||||
|
||||
A DSL stands for **Domain-Specific Language**, it is a programming or markup language designed for a specific application domain.
|
||||
Unlike general-purpose languages (like Python or Java), DSLs are optimized for a narrow set of problems, offering concise syntax and specialized features tailored to their domain.
|
||||
|
||||
Rougail format
|
||||
|
||||
The Rougail format (or :term:`structured data`) is a DSL (Domain-Specific Language) designed for describing variables and their consistency.
|
||||
|
||||
Declarative abstraction
|
||||
-----------------------
|
||||
|
||||
The variables are described using a declarative model.
|
||||
This means that the user simply defines the desired final state of the variable.
|
||||
:term:`Tiramisu` will then determine the actions necessary to reach that state.
|
||||
|
||||
In other words, the user defines the variable schema, which will then be applied deterministically.
|
||||
|
||||
The language is a mix of YAML 1.2 and Jinja Templating.
|
||||
|
||||
Each variables are declared in a mapping object in YAML (the keys are variable properties).
|
||||
|
||||
There is an execption. That what we call the short-hand declaration.
|
||||
|
||||
.. glossary::
|
||||
|
||||
Short-hand notation
|
||||
|
||||
Shorthand notation allows you to condense as much information as possible when creating a variable.
|
||||
Generally, the declaration is done on a single line (or at most, a very small number of lines).
|
||||
|
||||
Of course, it's not possible to fully customize the variable with this notation.
|
||||
|
||||
Use shorthand notation whenever possible. This makes the file easier to read.
|
||||
|
||||
Versioned format
|
||||
----------------
|
||||
|
||||
The format can evolve. This means that parameters can be added, removed, or modified.
|
||||
When writing structured data, you must always specify the format version.
|
||||
You must also ensure that your Rougail version is compatible with your format version.
|
||||
|
||||
191
docs/structured_data/typing.rst
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
Typing
|
||||
======
|
||||
|
||||
The typed variable concept refers to associating a data type with a variable, which defines what kind of values the variable can hold and what operations can be performed on it.
|
||||
|
||||
Typed variables are a fundamental feature in Rougail. Type validation is the first and most important quality check.
|
||||
|
||||
Strongly-typed
|
||||
--------------
|
||||
|
||||
Rougail is a strongly-typed DSL.
|
||||
|
||||
This means that loading user data requires attention to the variable types.
|
||||
|
||||
The :term:`integrator` define the variable type and the :term:`operator` has to conform with it.
|
||||
|
||||
.. For untyped user data (such as environment variables), the value type will be adapted during preprocessing.
|
||||
|
||||
Dynamicaly-typed
|
||||
----------------
|
||||
|
||||
During the structured data definition, the type is dynamic.
|
||||
|
||||
That is to say, the :term:`integrator` can change the type of the variable at any time.
|
||||
|
||||
However, the :term:`operator` who adapts the value does not have the possibility of redefining the type of the variable.
|
||||
|
||||
.. seealso:: :ref:`the variable mutability <variable_mutability>`
|
||||
|
||||
|
||||
Type inference
|
||||
--------------
|
||||
|
||||
Type inference is the process where Rougail automatically figures out the types without explicit annotations.
|
||||
In fact, the variable type comes from the type of its default value.
|
||||
|
||||
The type inference is in particular use with the :term:`short-hand notation`.
|
||||
|
||||
Variables typing
|
||||
----------------
|
||||
|
||||
Standard types
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Rougail accepts the following standard types:
|
||||
|
||||
- `string` (default type of a variable)
|
||||
- `integer`
|
||||
- `float`
|
||||
- `boolean`
|
||||
|
||||
.. FIXME: est-ce que integer et float -> number type ????
|
||||
|
||||
.. seealso:: :doc:`the variable documentation <variable>`
|
||||
|
||||
Specialized types
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
But we will also find a whole series of specialized types:
|
||||
|
||||
- IP
|
||||
- domainname
|
||||
- port
|
||||
- MAC
|
||||
- secret
|
||||
- ...
|
||||
|
||||
.. seealso:: :doc:`the variable documentation <variable>`
|
||||
|
||||
A variable with a list of possible values
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Sometimes a variable can only hold a finite list of possible values. We call it a variable with a list of possible values.
|
||||
|
||||
.. seealso:: The tutorial with a real world sample about :doc:`a variable with a list of possible values <../tutorial/choice>`
|
||||
|
||||
Type parameters
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
For certain types, there are a number of parameters that can be used to further type the variables.
|
||||
|
||||
.. seealso:: :doc:`the variable documentation <variable>`
|
||||
|
||||
.. _nullable_variable:
|
||||
|
||||
Custom type
|
||||
~~~~~~~~~~~
|
||||
|
||||
It is not possible to create every possible type of variable.
|
||||
|
||||
Therefore, it is necessary to provide a simple way to create these custom types.
|
||||
|
||||
There are two ways to create a type:
|
||||
|
||||
- creating a :term:`Tiramisu` type
|
||||
- creating a type from an existing variable, have a look at the tutorial with a real world sample :doc:`custom type <../tutorial/customtype>`.
|
||||
|
||||
Nullable variable
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
The `null` type (or `None` in Python) does not exist in Rougail.
|
||||
|
||||
All variables, regardless of their type, can be nullable (see the remarks on the list type below).
|
||||
|
||||
Even if all types can accept this value, by default, they do not.
|
||||
|
||||
In reality, the variable not nullable with the value to `null` is not accessible in `read-only` mode (which is the case during the output steps).
|
||||
In `read/write` mode, the access is indeed granted.
|
||||
|
||||
.. seealso:: The tutorial with a real world sample about a :doc:`nullable variable <../tutorial/nullable>`
|
||||
|
||||
The `list` type
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
A list is not a type either.
|
||||
It is a property of a variable. There is no such thing as a container type (like a python `list` type for instance).
|
||||
This means that all type can have multiple values in a list but it can only contain values of an unique type.
|
||||
|
||||
A multiple variable could be nullable. This means that `null` can be accepted as a value in the list (not permitted by default).
|
||||
But the multiple variable could also be without value (not permitted too by default).
|
||||
|
||||
.. seealso:: The tutorial with a real world sample about a :doc:`multiple variable <../tutorial/multiple>`
|
||||
|
||||
Families typing
|
||||
---------------
|
||||
|
||||
The `mapping` type
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A mapping is a collection of key: value pairs.
|
||||
|
||||
This is a JSON example:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"my_variable": "my_value"
|
||||
}
|
||||
|
||||
In Rougail the mapping type is called a :term:`family`.
|
||||
It is a container designed to hold variables.
|
||||
|
||||
The whole :term:`configuration` tree structure is handled by the families definitions.
|
||||
It is possible to create subfamilies.
|
||||
|
||||
.. seealso:: :doc:`the family documentation <family>`
|
||||
|
||||
.. _dynamically_built_family:
|
||||
|
||||
The dynamically built family
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A dynamically built family is a special family.
|
||||
|
||||
.. glossary::
|
||||
|
||||
dynamically built family
|
||||
|
||||
A dynamically built family is a fictitious family linked to a list of unique identifiers.
|
||||
|
||||
This means that families will appear or disappear folling the :term:`context`.
|
||||
|
||||
.. seealso:: :doc:`the dynamically built family documentation <family>`
|
||||
|
||||
Homogeneous elements sequence
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. glossary::
|
||||
|
||||
sequence
|
||||
homogeneous elements sequence
|
||||
|
||||
A specific type of mapping, called a `sequence`, allows you to have a list of homogeneous objects.
|
||||
|
||||
For example, if I want to be able to create an unlimited number of users associated with a secret, you can't use lists; I need a list of objects.
|
||||
|
||||
In JSON we will have:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
[
|
||||
{
|
||||
"user": "login1",
|
||||
"secret": "MySecret"
|
||||
},
|
||||
{
|
||||
"user": "login2",
|
||||
"secret": "MySecret"
|
||||
}
|
||||
]
|
||||
|
||||
45
docs/structured_data/variable_properties.rst
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
Properties
|
||||
==========
|
||||
|
||||
.. FIXME: duplicate from tutorial/properties.rst
|
||||
|
||||
Access control is achieved through `properties`.
|
||||
|
||||
.. glossary::
|
||||
|
||||
property
|
||||
|
||||
A property is a state (`disabled`, `mandatory`, `frozen`, `hidden`...)
|
||||
of a family or a variable.
|
||||
These properties change the usual behavior of a variable or family.
|
||||
|
||||
The properties can be defined permanently or according to the result of a calculation.
|
||||
|
||||
There are two main properties.
|
||||
|
||||
.. _hidden:
|
||||
|
||||
Hidden variable
|
||||
---------------
|
||||
|
||||
A `hidden` variable is a variable whose value cannot be modified by the :term:`operator`.
|
||||
|
||||
This could be an internal variable used by the :term:`integrator` that is not supposed to change.
|
||||
|
||||
Or a variable that only makes sense in a particular context. Therefore, this variable can be hidden and then unhidden depending on the context.
|
||||
|
||||
.. _disabled:
|
||||
|
||||
Disabled variable
|
||||
-----------------
|
||||
|
||||
A `disabled` variable is a variable that will not be accessible to any of the actors (:term:`integrator` and :term:`operator`).
|
||||
|
||||
This property is generally used dynamically to remove access to the variable depending on the context.
|
||||
|
||||
A picture is worth a thousand words:
|
||||
|
||||
.. image:: ../images/dessin.png
|
||||
|
||||
|
||||
.. index:: overall coherence
|
||||
8
docs/structured_data/variable_validation.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
Validation
|
||||
===========
|
||||
|
||||
Type validation is the first and most important check.
|
||||
But it is possible to add additional validations.
|
||||
|
||||
For example, one might want numbers, but only odd numbers.
|
||||
|
||||
41
docs/tiramisu.rst
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
Link between Rougail and Tiramisu
|
||||
======================================
|
||||
|
||||
Is Rougail using Tiramisu?
|
||||
-------------------------------------
|
||||
|
||||
We have to say that the handling system used to ensure the variables integrity is another python library, called :term:`Tiramisu`. Rougail is currently strongly affiliated with Tiramisu.
|
||||
|
||||
.. note:: Rougail is currently intended to work in coordination with :term:`Tiramisu` and **is not** intended to be connected with any other consistency handling system.
|
||||
|
||||
Explained differently, Rougail allows you to easily implement an integration of the powerful :term:`Tiramisu` consistency handling system.
|
||||
|
||||
What is a consistency handling system?
|
||||
-------------------------------------------
|
||||
|
||||
.. questions:: Rougail, Tiramisu: What is it all about?
|
||||
|
||||
**Question**: OK, I have understood that the Rougail library allows me to take advantage of the :xref:`tiramisu` consistency handling library. But what is all this for? What is exactly a consistency handling system? And again, what is this :xref:`Tiramisu library <tiramisu library>` used for?
|
||||
|
||||
**Answer**: Well, we will explain in details what this :xref:`tiramisu` library is and what Rougail is.
|
||||
|
||||
In (very) short:
|
||||
|
||||
- Rougail is the YAML consistency description of a :term:`context`\ 's situation
|
||||
- Tiramisu is the consistency engine linter
|
||||
|
||||
.. glossary::
|
||||
|
||||
Tiramisu
|
||||
|
||||
:xref:`tiramisu` is a consistency handling system that has initially been designed
|
||||
in the configuration management scope. Until now,
|
||||
this library is generally used to handle configuration options.
|
||||
|
||||
It manages variables and group of variables. In the Tiramisu scope we call
|
||||
it *options* and *option descriptions*.
|
||||
|
||||
Here is the :xref:`tiramisu documentation <tiramisu>`.
|
||||
|
||||
In the Rougail scope, we call it :term:`variables <variable>` and :term:`families <family>`.
|
||||
In Rougail, the families and variables are located in the :term:`structure files <structure file>`.
|
||||
|
|
@ -1,832 +0,0 @@
|
|||
Tutorial: a real world sample
|
||||
==============================
|
||||
|
||||
.. demo:: Demonstration : configuring (the setting of) your favorite web browser
|
||||
|
||||
This tutorial shows to you an example of Rougail use on
|
||||
how to set a proxy in the `Mozilla Firefox <https://www.mozilla.org/en-US/firefox/new/>`_ browser.
|
||||
|
||||
More precisely, this tutorial aims at reproducing this Mozilla Firefox settings page:
|
||||
|
||||
.. image:: images/firefox.png
|
||||
|
||||
.. important:: Here we are in the configuration validation use case,
|
||||
that is the values entered by the user have to be validated.
|
||||
It's a common use case, but not the only one.
|
||||
|
||||
Let's explain this use case.
|
||||
|
||||
The Firefox proxy configuration
|
||||
-------------------------------------------
|
||||
|
||||
The `proxy` family
|
||||
-------------------
|
||||
|
||||
Let's create our first :term:`dictionary`.
|
||||
|
||||
.. prerequisites:: Let's create a folder named `dict` and a dictionary file inside
|
||||
|
||||
We will put our dictionary files in this folder.
|
||||
|
||||
Then let's put our first dictionary file in this folder, named :file:`00-proxy.yml`
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: the :file:`00-proxy.yml` file
|
||||
:linenos:
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
proxy:
|
||||
description: Proxy configuration in order to have access to the internet
|
||||
type: family
|
||||
|
||||
We can see that we have defined a :term:`family` here, and this family is *empty*
|
||||
(that is, the family container contains no variable yet).
|
||||
|
||||
.. admonition:: If a family is empty
|
||||
|
||||
We need to specify the :term:`family` type (line 5) here because if we don't,
|
||||
the Rougail's type engine will infer it by default as a :term:`variable`.
|
||||
|
||||
It's because we don't have set any :term:`variable` inside.
|
||||
|
||||
|
||||
.. note:: The variables will be created in several files for educational purposes.
|
||||
Obviously all the variables can be put in the same file.
|
||||
|
||||
|
||||
The proxy's configuration type
|
||||
----------------------------------
|
||||
|
||||
In the Firefox configuration, it is possible to define several configuration modes,
|
||||
from no proxy at all (`no proxy`) to a kind of automatic configuration mode from a file (`set up proxy configuration from a file`).
|
||||
|
||||
We're gonna create a first variable in this family with "Proxy mode" as the description.
|
||||
Let's create a second :file:`dict/01-proxy_mode.yml` file.
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: the :file:`001-proxy_mode.yml` file
|
||||
:linenos:
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
proxy:
|
||||
proxy_mode:
|
||||
description: Proxy mode
|
||||
type: choice
|
||||
choices:
|
||||
- No proxy
|
||||
- Auto-detect proxy settings for this network
|
||||
- Use system proxy settings
|
||||
- Manual proxy configuration
|
||||
- Automatic proxy configuration URL
|
||||
default: No proxy
|
||||
|
||||
The `proxy_mode` variable requires a value (that is, `None` is not an option).
|
||||
It shall have a value, but what if the user *does not* specify any value?
|
||||
There is line 13, a possibility of setting a default value, wich is `No proxy` as the default.
|
||||
|
||||
The `proxy_mode` setting is "choice" (`type: choice`) means that
|
||||
there is a list of available values that can be selected.
|
||||
We say that the `proxy_mode` variable is *constrained* (by choices).
|
||||
|
||||
Line 8 to 12, we have the list of the possible (authorized) values:
|
||||
|
||||
- No proxy
|
||||
- Auto-detect proxy settings for this network
|
||||
- Use system proxy settings
|
||||
- Manual proxy configuration
|
||||
- Automatic proxy configuration URL
|
||||
|
||||
Now let's test our first two dictionaries:
|
||||
|
||||
|
||||
>>> from rougail import Rougail, RougailConfig
|
||||
>>> from pprint import pprint
|
||||
>>> RougailConfig['dictionaries_dir'] = ['dict']
|
||||
>>> rougail = Rougail()
|
||||
>>> config = rougail.get_config()
|
||||
>>> config.property.read_only()
|
||||
>>> pprint(config.value.get(), sort_dicts=False)
|
||||
{'rougail.proxy.proxy_mode': 'No proxy'}
|
||||
|
||||
The manual mode
|
||||
------------------
|
||||
|
||||
.. questions:: OK then. What happens when you select the "Manual proxy configuration"?
|
||||
|
||||
A good configuration design is to place all the proxy's manual configuration in a :term:`family`.
|
||||
Let's create the :file:`dict/02-proxy_manual.yml` dictionary:
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: the the :file:`dict/02-proxy_manual.yml` file
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
proxy:
|
||||
manual:
|
||||
description: Manual proxy configuration
|
||||
type: family
|
||||
disabled:
|
||||
type: jinja
|
||||
jinja: |
|
||||
{% if rougail.proxy.proxy_mode != 'Manual proxy configuration' %}
|
||||
the proxy mode is not manual
|
||||
{% endif %}
|
||||
|
||||
Well, if the user selects the "Manual proxy configuration" proxy mode, we want to see a new subfamily (that is, a new set of configuration variables) called `manual` to appear (which is disabled).
|
||||
|
||||
.. glossary::
|
||||
|
||||
subfamily
|
||||
|
||||
A subfamily is just a family inside a family, a family that contains a family.
|
||||
|
||||
.. questions:: What about this `Jinja` type?
|
||||
|
||||
If the :term:`Jinja` template returns some text, then the family will be `disabled`. Otherwise it is accessible.
|
||||
Deactivating a family means that we will not be able to access it as well as the variables or families included in this family.
|
||||
|
||||
.. note:: If the Jinja template does not return any text, the variable will be **enabled**.
|
||||
Here we are using the Jinja condition statement.
|
||||
|
||||
.. glossary::
|
||||
|
||||
Jinja
|
||||
|
||||
`Jinja <https://jinja.palletsprojects.com>`_ is a template engine.
|
||||
we are using Jinja in a classical way, that is, Jinja allows us to handle different cases,
|
||||
for example with the `if` statement.
|
||||
|
||||
The HTTP proxy configuration
|
||||
------------------------------
|
||||
|
||||
In this family let's add a *subfamily* named `http_proxy`, containing the address and port configuration variables.
|
||||
|
||||
Let's create the :file:`dict/03-proxy_manual_http_proxy.yml` dictionary:
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: the the :file:`dict/02-proxy_manual.yml` file
|
||||
:linenos:
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
proxy:
|
||||
manual:
|
||||
http_proxy:
|
||||
description: HTTP Proxy
|
||||
address:
|
||||
description: HTTP address
|
||||
type: domainname
|
||||
port:
|
||||
description: HTTP Port
|
||||
type: port
|
||||
default: '8080'
|
||||
|
||||
Both variables `address` and `port` have particular types (respectively `domainname` line 9 and `port` line 12) to validate the values configured by the user.
|
||||
|
||||
.. note:: No need to specify the type of the `http_proxy` as a family type, because here we have declared variables inside of it.
|
||||
|
||||
Duplicating the HTTP configuration to HTTPS
|
||||
---------------------------------------------
|
||||
|
||||
We then want to offer the user the possibility of providing the same proxy for the HTTPS requests. Let's create the :file:`dict/04-proxy_manual_http_use_for_https.yml` file:
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: the :file:`dict/04-proxy_manual_http_use_for_https.yml` file
|
||||
|
||||
version: '1.1'
|
||||
proxy:
|
||||
manual:
|
||||
use_for_https:
|
||||
description: Also use this proxy for HTTPS
|
||||
type: boolean
|
||||
|
||||
This variable is a `boolean` type, its default value is `True`.
|
||||
|
||||
HTTPS proxy configuration detail
|
||||
-----------------------------------
|
||||
|
||||
Let's add a new subfamily named `ssl_proxy`, containing the `address` and `port` variables.
|
||||
|
||||
Let's create the :file:`dict/05-proxy_manual_ssl_proxy.yml` file:
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: the :file:`dict/04-proxy_manual_http_use_for_https.yml` file
|
||||
:linenos:
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
proxy:
|
||||
manual:
|
||||
ssl_proxy:
|
||||
description: HTTPS Proxy
|
||||
hidden:
|
||||
type: variable
|
||||
variable: rougail.proxy.manual.use_for_https
|
||||
address:
|
||||
description: HTTPS address
|
||||
type: domainname
|
||||
default:
|
||||
type: jinja
|
||||
jinja: |
|
||||
{% if rougail.proxy.manual.use_for_https %}
|
||||
{{ rougail.proxy.manual.http_proxy.address }}
|
||||
{% endif %}
|
||||
port:
|
||||
description: HTTPS Port
|
||||
type: port
|
||||
default:
|
||||
type: jinja
|
||||
jinja: |
|
||||
{% if rougail.proxy.manual.use_for_https %}
|
||||
{{ rougail.proxy.manual.http_proxy.port }}
|
||||
{% endif %}
|
||||
|
||||
|
||||
Depending on the value of the `rougail.proxy.mandatory.use_for_https` variable, this family will appear or disappear (the `hidden` setting line 7). Unlike earlier, this time it is not necessary to use a Jinja function.
|
||||
|
||||
Let's notice that the family is not disabled because the variables will need to remain accessible (yet in `read-only` mode).
|
||||
|
||||
The address and port variables are copied from HTTP to HTTPS if `rougail.proxy.use_for_https` is set to `True`.
|
||||
|
||||
Now let's test all of it:
|
||||
|
||||
>>> from rougail import Rougail, RougailConfig
|
||||
>>> from pprint import pprint
|
||||
>>> RougailConfig['dictionaries_dir'] = ['dict']
|
||||
>>> rougail = Rougail()
|
||||
>>> config = rougail.get_config()
|
||||
>>> config.property.read_only()
|
||||
>>> pprint(config.value.get(), sort_dicts=False)
|
||||
{'rougail.proxy.proxy_mode': 'No proxy'}
|
||||
|
||||
At this time the proxy is not configured yet, so we do not see any variables.
|
||||
Let's look at what happens if we try to access the `rougail.proxy.manual` variable if we are not in manual mode:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> pprint(config.option('rougail.proxy.manual').value.get(), sort_dicts=False)
|
||||
|
||||
We have an error (with the message defined in the Jinja template):
|
||||
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
tiramisu.error.PropertiesOptionError: cannot access to
|
||||
optiondescription "Manual proxy configuration" because
|
||||
has property "disabled" (the mode proxy is not manual)
|
||||
|
||||
|
||||
Let's configure the proxy in manual mode
|
||||
|
||||
>>> config.property.read_write()
|
||||
>>> config.option('rougail.proxy.proxy_mode').value.set('Manual proxy configuration')
|
||||
>>> config.option('rougail.proxy.manual.http_proxy.address').value.set('proxy.example')
|
||||
>>> pprint(config.value.get(), sort_dicts=False)
|
||||
|
||||
We can see that the returned variables does have the desired values:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
{'rougail.proxy.proxy_mode': 'Manual proxy configuration',
|
||||
'rougail.proxy.manual.http_proxy.address': 'proxy.example',
|
||||
'rougail.proxy.manual.http_proxy.port': '8080',
|
||||
'rougail.proxy.manual.use_for_https': True}
|
||||
|
||||
Let's set the `read_only` mode and have a look at the configuration again:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> config.property.read_only()
|
||||
>>> pprint(config.value.get(), sort_dicts=False)
|
||||
{'rougail.proxy.proxy_mode': 'Manual proxy configuration',
|
||||
'rougail.proxy.manual.http_proxy.address': 'proxy.example',
|
||||
'rougail.proxy.manual.http_proxy.port': '8080',
|
||||
'rougail.proxy.manual.use_for_https': True,
|
||||
'rougail.proxy.manual.ssl_proxy.address': 'proxy.example',
|
||||
'rougail.proxy.manual.ssl_proxy.port': '8080'}
|
||||
|
||||
In the `read_only` mode, we can see that the HTTPS configuration appears.
|
||||
|
||||
.. note:: We can see that `rougail.proxy.manual.http_proxy` values have been copied
|
||||
in `rougail.proxy.manual.ssl_proxy` too.
|
||||
|
||||
Changing values programmatically
|
||||
--------------------------------------
|
||||
|
||||
We are going to use the :term:`Tiramisu` API to manipulate programmatically the different variables.
|
||||
|
||||
First, let's set `rougail.proxy.manual.use_for_https` to `False`. It is now possible
|
||||
to configure the HTTPS:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> config.property.read_write()
|
||||
>>> config.option('rougail.proxy.manual.use_for_https').value.set(False)
|
||||
>>> config.option('rougail.proxy.manual.ssl_proxy.address').value.set('other.proxy.example')
|
||||
>>> pprint(config.value.get(), sort_dicts=False)
|
||||
{'rougail.proxy.proxy_mode': 'Manual proxy configuration',
|
||||
'rougail.proxy.manual.http_proxy.address': 'proxy.example',
|
||||
'rougail.proxy.manual.http_proxy.port': '8080',
|
||||
'rougail.proxy.manual.use_for_https': False,
|
||||
'rougail.proxy.manual.ssl_proxy.address': 'other.proxy.example',
|
||||
'rougail.proxy.manual.ssl_proxy.port': '8080'}
|
||||
|
||||
The value of the variable `rougail.proxy.manual.ssl_proxy.address` has actually been modified.
|
||||
But if this variable is hidden again, then the value comes back to the default value:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> config.option('rougail.proxy.manual.use_for_https').value.set(False)
|
||||
>>> config.property.read_only()
|
||||
>>> pprint(config.value.get(), sort_dicts=False)
|
||||
{'rougail.proxy.proxy_mode': 'Manual proxy configuration',
|
||||
'rougail.proxy.manual.http_proxy.address': 'proxy.example',
|
||||
'rougail.proxy.manual.http_proxy.port': '8080',
|
||||
'rougail.proxy.manual.use_for_https': False,
|
||||
'rougail.proxy.manual.ssl_proxy.address': 'proxy.example',
|
||||
'rougail.proxy.manual.ssl_proxy.port': '8080'}
|
||||
|
||||
SOCK's proxy configuration
|
||||
-------------------------------
|
||||
|
||||
Let's add a new :term:`subfamily` named `socks_proxy` with the `address`,
|
||||
`port` and `version` variables.
|
||||
|
||||
Let's create the :file:`dict/06-proxy_manual_socks_proxy.yml` file:
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: the :file:`dict/06-proxy_manual_socks_proxy.yml` file
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
proxy:
|
||||
manual:
|
||||
socks_proxy:
|
||||
description: SOCKS Proxy
|
||||
address:
|
||||
description: SOCKS Address
|
||||
type: domainname
|
||||
port:
|
||||
description: SOCKS Port
|
||||
type: port
|
||||
version:
|
||||
description: SOCKS host version used by proxy
|
||||
type: choice
|
||||
choices:
|
||||
- v4
|
||||
- v5
|
||||
default: v5
|
||||
|
||||
There's nothing new to learn with this file.
|
||||
|
||||
The automatic detection mode
|
||||
------------------------------
|
||||
|
||||
Let's add a new variable named `auto`.
|
||||
|
||||
Let's create the :file:`dict/07-proxy_auto.yml` file:
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: the :file:`dict/07-proxy_auto.yml` file
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
proxy:
|
||||
auto:
|
||||
type: web_address
|
||||
description: Automatic proxy configuration URL
|
||||
disabled:
|
||||
type: jinja
|
||||
jinja: |
|
||||
{% if rougail.proxy.proxy_mode != 'Automatic proxy configuration URL' %}
|
||||
the proxy mode is not automatic
|
||||
{% endif %}
|
||||
|
||||
The `web_address` type imposes a value starting with `http://` or `https://`.
|
||||
This variable is activated when the proxy is in automatic mode.
|
||||
|
||||
The proxy's exceptions
|
||||
---------------------------
|
||||
|
||||
Finally, let's add a variable containing proxy exceptions.
|
||||
|
||||
Let's create the :file:`dict/07-proxy_no_proxy.yml` file:
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: the :file:`dict/07-proxy_no_proxy.yml` file
|
||||
:linenos:
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
proxy:
|
||||
no_proxy:
|
||||
description: Address for which proxy will be desactivated
|
||||
multi: true
|
||||
type: "domainname"
|
||||
params:
|
||||
allow_ip: true
|
||||
allow_cidr_network: true
|
||||
allow_without_dot: true
|
||||
allow_startswith_dot: true
|
||||
disabled:
|
||||
type: jinja
|
||||
jinja: |
|
||||
{% if rougail.proxy.proxy_mode == 'No proxy' %}
|
||||
proxy mode is no proxy
|
||||
{% endif %}
|
||||
mandatory: false
|
||||
|
||||
This `no_proxy` variable is much like a `domainname` type except that we add
|
||||
a `params` line 7, we authorize the :
|
||||
|
||||
- IP
|
||||
- CIDR networks
|
||||
- machine names (without `'.'`)
|
||||
- sub-domaines like `.example`
|
||||
|
||||
There can be multiple exceptions to the proxy, so the variable is :term:`multi` (line5).
|
||||
This variable is only accessible if no proxy is defined (`disabled`).
|
||||
|
||||
.. glossary::
|
||||
|
||||
multi
|
||||
|
||||
A multi is a multiple variable, that is a variable that can have multiple values.
|
||||
|
||||
|
||||
The `no_proxy` variable do not requires a value (that is, `None` is an option),
|
||||
there is line 19 this statement `mandatory: false` which means that this variable is not mandatory.
|
||||
|
||||
|
||||
Let's test it:
|
||||
|
||||
|
||||
>>> from rougail import Rougail, RougailConfig
|
||||
>>> from pprint import pprint
|
||||
>>> RougailConfig['dictionaries_dir'] = ['dict']
|
||||
>>> rougail = Rougail()
|
||||
>>> config = rougail.get_config()
|
||||
>>> config.property.read_write()
|
||||
>>> config.option('rougail.proxy.proxy_mode').value.set('Manual proxy configuration')
|
||||
>>> config.option('rougail.proxy.manual.http_proxy.address').value.set('proxy.example')
|
||||
>>> config.option('rougail.proxy.no_proxy').value.set(['.example', '192.168.1.1'])
|
||||
>>> config.property.read_only()
|
||||
>>> pprint(config.value.get(), sort_dicts=False)
|
||||
|
||||
It outputs:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
{'rougail.proxy.proxy_mode': 'Manual proxy configuration',
|
||||
'rougail.proxy.manual.http_proxy.address': 'proxy.example',
|
||||
'rougail.proxy.manual.http_proxy.port': '8080',
|
||||
'rougail.proxy.manual.use_for_https': True,
|
||||
'rougail.proxy.manual.ssl_proxy.address': 'proxy.example',
|
||||
'rougail.proxy.manual.ssl_proxy.port': '8080',
|
||||
'rougail.proxy.manual.socks_proxy.address': None,
|
||||
'rougail.proxy.manual.socks_proxy.port': None,
|
||||
'rougail.proxy.manual.socks_proxy.version': 'v5',
|
||||
'rougail.proxy.no_proxy': ['.example', '192.168.1.1']}
|
||||
|
||||
But not possible to put an invalid value:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> config.option('rougail.proxy.no_proxy').value.set(['.example', '192.168.1.1', 'not valid'])
|
||||
[..]
|
||||
tiramisu.error.ValueOptionError: "not valid" is an invalid domain name for "Address for which proxy will be desactivated", could be a IP, otherwise must start with lowercase characters followed by lowercase characters, number, "-" and "." characters are allowed
|
||||
|
||||
|
||||
The authentification request
|
||||
--------------------------------
|
||||
|
||||
Nothing special when creating the authentication request. To do this, let's create a `dict/08-proxy_prompt_authentication.yml` file:
|
||||
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: the :file:`dict/08-proxy_prompt_authentication.yml` file
|
||||
:linenos:
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
proxy:
|
||||
prompt_authentication:
|
||||
description: Prompt for authentication if password is saved
|
||||
type: boolean
|
||||
default: true
|
||||
disabled:
|
||||
type: jinja
|
||||
jinja: |
|
||||
{% if rougail.proxy.proxy_mode == 'No proxy' %}
|
||||
proxy mode is no proxy
|
||||
{% endif %}
|
||||
|
||||
The proxy SOCKS v5's DNS
|
||||
------------------------------
|
||||
|
||||
The DNS variable for the SOCKS v5 proxy only appears if the proxy is configured and the version of the SOCKS proxy selected is `v5`.
|
||||
|
||||
Let's create a `dict/09-proxy_proxy_dns_socks5.yml` file:
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: the :file:`dict/09-proxy_proxy_dns_socks5.yml` file
|
||||
:linenos:
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
proxy:
|
||||
proxy_dns_socks5:
|
||||
description: Use proxy DNS when using SOCKS v5
|
||||
type: boolean
|
||||
default: false
|
||||
disabled:
|
||||
type: jinja
|
||||
params:
|
||||
socks_version:
|
||||
type: variable
|
||||
variable: rougail.proxy.manual.socks_proxy.version
|
||||
propertyerror: false
|
||||
jinja: |
|
||||
{% if rougail.proxy.proxy_mode == 'No proxy' %}
|
||||
the proxy mode is no proxy
|
||||
{% elif socks_version is undefined or socks_version == 'v4' %}
|
||||
socks version is v4
|
||||
{% endif %}
|
||||
|
||||
The difficulty here is that the `rougail.proxy.manual.socks_proxy.version` variable
|
||||
can be deactivated (and therefore not usable in a calculation).
|
||||
|
||||
.. FIXME definir ce qu'est une calculation
|
||||
|
||||
In this case, we will add a parameter (here called `socks_version`) which will contain,
|
||||
if there is no property error, the value of the variable.
|
||||
Otherwise the parameter will not be passed to the Jinja template.
|
||||
|
||||
This is why it is necessary to test in the Jinja template whether the `socks_version` variable really exists.
|
||||
|
||||
The DNS over HTTPS
|
||||
----------------------
|
||||
|
||||
Finally we will configure DNS over HTTPS in the 10-proxy_dns_over_https.yml file:
|
||||
|
||||
Let's create a `dict/10-proxy_dns_over_https.yml` file:
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: the :file:`dict/10-proxy_dns_over_https.yml` file
|
||||
:linenos:
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
proxy:
|
||||
dns_over_https:
|
||||
description: DNS over HTTPS
|
||||
enable_dns_over_https:
|
||||
description: Enable DNS over HTTPS
|
||||
type: boolean
|
||||
default: false
|
||||
provider:
|
||||
description: Use Provider
|
||||
type: choice
|
||||
choices:
|
||||
- Cloudflare
|
||||
- NextDNS
|
||||
- Custom
|
||||
default: Cloudflare
|
||||
disabled:
|
||||
type: jinja
|
||||
jinja: |
|
||||
{% if not rougail.proxy.dns_over_https.enable_dns_over_https %}
|
||||
Enable DNS over HTTPS is False
|
||||
{% endif %}
|
||||
custom_dns_url:
|
||||
description: Custom DNS URL
|
||||
type: web_address
|
||||
disabled:
|
||||
type: jinja
|
||||
params:
|
||||
provider:
|
||||
type: variable
|
||||
variable: rougail.proxy.dns_over_https.provider
|
||||
propertyerror: false
|
||||
jinja: |
|
||||
{% if provider is not defined or provider != 'Custom' %}
|
||||
provider is not custom
|
||||
{% endif %}
|
||||
validators:
|
||||
- type: jinja
|
||||
jinja: |
|
||||
{% if rougail.proxy.dns_over_https.custom_dns_url.startswith('http://') %}
|
||||
only https is allowed
|
||||
{% endif %}
|
||||
|
||||
.. FIXME : define validators
|
||||
|
||||
The only particularity here is that we added additional validation (validators) to the `custom_dns_url` variable. Only an address starting with `https://` is allowed (not `http://`).
|
||||
|
||||
----
|
||||
|
||||
The FoxyProxy type's proxy configuration
|
||||
--------------------------------------------
|
||||
|
||||
Here is now the integration of part of the Firefox FoxyProxy plugin.
|
||||
|
||||
The idea is to have a namespace specific to FoxyProxy and to find in it part of the settings that we will have made in the main namespace.
|
||||
|
||||
This is what the page looks like:
|
||||
|
||||
.. image:: images/foxyproxy.png
|
||||
|
||||
It is possible, in this plugin, to specify an unlimited number of proxies.
|
||||
Our `proxy` family will no longer be of the `family` type as before but of another type : the :term:`leadership` type.
|
||||
|
||||
.. FIXME: expliquer ce qu'est le type leardership
|
||||
|
||||
Here is the complete content of the FoxyProxy type proxy configuration
|
||||
(to be put in the `foxyproxy/00-base.yml` file):
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: the :file:``foxyproxy/00-base.yml`` file
|
||||
:linenos:
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
proxy:
|
||||
_type: leadership
|
||||
title:
|
||||
description: Title or Description
|
||||
multi: true
|
||||
color:
|
||||
description: Color
|
||||
type:
|
||||
type: choice
|
||||
choices:
|
||||
- HTTP
|
||||
- HTTPS/SSL
|
||||
- SOCKS5
|
||||
- SOCKS4
|
||||
- PAC URL
|
||||
- WPAD
|
||||
- System (use system settings)
|
||||
- Direct (no proxy)
|
||||
default: Direct (no proxy)
|
||||
address:
|
||||
description: IP address, DNS name, server name
|
||||
multi: true
|
||||
disabled:
|
||||
type: jinja
|
||||
jinja: |
|
||||
{% if foxyproxy.proxy.type not in ['HTTP', 'HTTPS/SSL', 'SOCKS5', 'SOCKS4'] %}
|
||||
proxy does not need address
|
||||
{% endif %}
|
||||
default:
|
||||
type: jinja
|
||||
params:
|
||||
firefox_address:
|
||||
type: variable
|
||||
variable: rougail.proxy.manual.http_proxy.address
|
||||
propertyerror: false
|
||||
jinja: |
|
||||
{% if firefox_address is not undefined %}
|
||||
{{ firefox_address }}
|
||||
{% endif %}
|
||||
port:
|
||||
description: Port
|
||||
type: port
|
||||
default:
|
||||
type: jinja
|
||||
params:
|
||||
firefox_port:
|
||||
type: variable
|
||||
variable: rougail.proxy.manual.http_proxy.port
|
||||
propertyerror: false
|
||||
jinja: |
|
||||
{% if firefox_port is not undefined %}
|
||||
{{ firefox_port }}
|
||||
{% endif %}
|
||||
disabled:
|
||||
type: jinja
|
||||
jinja: |
|
||||
{% if foxyproxy.proxy.type not in ['HTTP', 'HTTPS/SSL', 'SOCKS5', 'SOCKS4'] %}
|
||||
proxy does not need port
|
||||
{% endif %}
|
||||
username:
|
||||
description: Username
|
||||
type: unix_user
|
||||
mandatory:
|
||||
type: jinja
|
||||
jinja: |
|
||||
{% if foxyproxy.proxy.password %}
|
||||
username is mandatory
|
||||
{% endif %}
|
||||
disabled:
|
||||
type: jinja
|
||||
jinja: |
|
||||
{% if foxyproxy.proxy.type not in ['HTTP', 'HTTPS/SSL', 'SOCKS5', 'SOCKS4'] %}
|
||||
proxy does not need username
|
||||
{% endif %}
|
||||
password:
|
||||
description: Password
|
||||
type: secret
|
||||
disabled:
|
||||
type: jinja
|
||||
jinja: |
|
||||
{% if foxyproxy.proxy.type not in ['HTTP', 'HTTPS/SSL', 'SOCKS5', 'SOCKS4'] %}
|
||||
proxy does not need password
|
||||
{% endif %}
|
||||
url:
|
||||
type: web_address
|
||||
disabled:
|
||||
type: jinja
|
||||
jinja: |
|
||||
{% if foxyproxy.proxy.type not in ['PAC URL', 'WPAD'] %}
|
||||
proxy does not need url
|
||||
{% endif %}
|
||||
|
||||
|
||||
A few comments:
|
||||
|
||||
- in the `foxyproxy.proxy` :term:`leader` family there is a variable named `type` (line 4), this may conflict with the `type` attribute (specified line 10). In this case, to specify the type we use the `_type` attribute
|
||||
- a :term:`follower` variable can also be multiple
|
||||
(which is the case for `foxyproxy.proxy.address`)
|
||||
- `foxyproxy.proxy.username` (line 62) becomes :term:`mandatory` if `foxyproxy.proxy.password`
|
||||
is specified, in fact a password without a username is meaningless
|
||||
|
||||
Let's test it:
|
||||
|
||||
>>> from rougail import Rougail, RougailConfig
|
||||
>>> from pprint import pprint
|
||||
>>> RougailConfig['dictionaries_dir'] = ['dict']
|
||||
>>> RougailConfig['extra_dictionaries']['foxyproxy'] = ['foxyproxy/']
|
||||
>>> rougail = Rougail()
|
||||
>>> config = rougail.get_config()
|
||||
>>> config.option('rougail.proxy.proxy_mode').value.set('Manual proxy configuration')
|
||||
>>> config.option('rougail.proxy.manual.http_proxy.address').value.set('proxy.example')
|
||||
>>> config.option('foxyproxy.proxy.title').value.set(['MyProxy'])
|
||||
>>> config.option('foxyproxy.proxy.type', 0).value.set('HTTP')
|
||||
>>> config.option('foxyproxy.proxy.color', 0).value.set('#00000')
|
||||
>>> config.property.read_only()
|
||||
>>> pprint(config.value.get(), sort_dicts=False)
|
||||
|
||||
The output is:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
{'rougail.proxy.proxy_mode': 'Manual proxy configuration',
|
||||
'rougail.proxy.manual.http_proxy.address': 'proxy.example',
|
||||
'rougail.proxy.manual.http_proxy.port': '8080',
|
||||
'rougail.proxy.manual.use_for_https': True,
|
||||
'rougail.proxy.manual.ssl_proxy.address': 'proxy.example',
|
||||
'rougail.proxy.manual.ssl_proxy.port': '8080',
|
||||
'rougail.proxy.manual.socks_proxy.address': None,
|
||||
'rougail.proxy.manual.socks_proxy.port': None,
|
||||
'rougail.proxy.manual.socks_proxy.version': 'v5',
|
||||
'rougail.proxy.no_proxy': [],
|
||||
'rougail.proxy.proxy_dns_socks5': False,
|
||||
'rougail.proxy.dns_over_https.enable_dns_over_https': False,
|
||||
'foxyproxy.proxy.title': [{'foxyproxy.proxy.title': 'MyProxy',
|
||||
'foxyproxy.proxy.color': '#00000',
|
||||
'foxyproxy.proxy.type': 'HTTP',
|
||||
'foxyproxy.proxy.address': ['proxy.example'],
|
||||
'foxyproxy.proxy.port': '8080',
|
||||
'foxyproxy.proxy.username': None,
|
||||
'foxyproxy.proxy.password': None}]}
|
||||
|
||||
The choice we made here is to make `foxyproxy.proxy.username` :term:`mandatory` if a password is specified in the `foxyproxy.proxy.password` variable.
|
||||
|
||||
It makes sense to have a username without a password (in this case the password will be requested when connecting to the proxy). But the opposite does not make sense.
|
||||
|
||||
From a user point of view this may seem disturbing (if you enter the password, you have to return to the previous option to specify the password).
|
||||
|
||||
It is possible to reverse the logic. If the `foxyproxy.proxy.username` variable is set, the `foxyproxy.proxy.password` variable becomes editable.
|
||||
|
||||
None of this two variables needs to be :term:`mandatory`.
|
||||
|
||||
If you prefer this option, here is a second extra dictionary :file:`foxyproxy/01-redefine.yml` which will redefine the behavior only of the `foxyproxy.proxy.username` and `foxyproxy.proxy.password` variables:
|
||||
|
||||
|
||||
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: the :file:`foxyproxy/01-redefine.yml` file
|
||||
:linenos:
|
||||
|
||||
---
|
||||
version: '1.1'
|
||||
proxy:
|
||||
username:
|
||||
redefine: true
|
||||
# suppress mandatory constrainte
|
||||
mandatory: false
|
||||
password:
|
||||
redefine: true
|
||||
hidden:
|
||||
type: jinja
|
||||
jinja: |
|
||||
{% if not foxyproxy.proxy.username %}
|
||||
no username defined
|
||||
{% endif %}
|
||||
|
||||
|
||||
**It's up to you to play now !**
|
||||
62
docs/tutorial/auto_save.rst
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
Auto save value
|
||||
===============
|
||||
|
||||
.. objectives:: Objectives
|
||||
|
||||
A default value is a value that can be recalculated at different times. It can be useful to consider the default value as a modified value.
|
||||
|
||||
.. prerequisites:: Prerequisites
|
||||
|
||||
- We assume that Rougail's library is :ref:`installed <installation>` on your computer.
|
||||
|
||||
- It is possible to retrieve the current state of the various Rougail files manipulated in this tutorial step
|
||||
by checking out the corresponding tag of the `rougail-tutorials` git repository.
|
||||
Each tag corresponds to a stage of progress in the tutorial.
|
||||
Of course, you can also decide to copy/paste or download the tutorial files contents while following the tutorial steps.
|
||||
|
||||
If you want to follow this tutorial with the help of the corresponding :tutorial:`rougail-tutorials git repository <src/branch/1.1>`,
|
||||
this workshop page corresponds to the tag :tutorial:`v1.1_210 <src/tag/v1.1_210/README.md>`
|
||||
|
||||
::
|
||||
|
||||
git clone https://forge.cloud.silique.fr/stove/rougail-tutorials.git
|
||||
git switch --detach v1.1_210
|
||||
|
||||
The :ref:`configuration` is loaded into :term:`Tiramisu`. In this case, the default values are cached upon the first access to the variable. However, sometimes this value will be recalculated.
|
||||
If the default value is random, this can cause problems. Indeed, the value can change over time.
|
||||
|
||||
The `auto_save` property allows you to say that the calculated value will be considered as modified (therefore not recalculated) on the first access to this variable.
|
||||
|
||||
Remember, we just performed a random calculation for the variable `color`:
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_201/foxyproxy/00-foxyproxy.yml
|
||||
:language: yaml
|
||||
:caption: Calculate the default variable `color`.
|
||||
|
||||
We just need to set the `auto_save` property to true on this variable:
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_210/foxyproxy/00-foxyproxy.yml
|
||||
:language: yaml
|
||||
:caption: Auto_save for the variable `color`.
|
||||
|
||||
Test this variable with this Rougail CLI:
|
||||
|
||||
.. raw:: html
|
||||
:class: terminal
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_210/config/02/cmd_ro.txt
|
||||
|
||||
We have this output:
|
||||
|
||||
.. raw:: html
|
||||
:class: output
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_210/config/02/output_ro.html
|
||||
|
||||
As you can see, the value is the color of the modified variables.
|
||||
|
||||
.. note::
|
||||
|
||||
We do not save this value. It is therefore stored in memory. When the Rougail CLI closes, this value is forgotten. It will be recalculated if you run the command again.
|
||||
|
||||
.. keypoints:: Key points
|
||||
|
||||
We can auto save a variable.
|
||||
275
docs/tutorial/calculated.rst
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
Calculated default value for a variable
|
||||
============================================
|
||||
|
||||
.. objectives:: Objectives
|
||||
|
||||
In this section we will reuse the value of a variable for the default value of another variable.
|
||||
|
||||
We will first build the `https_proxy` family which will be used to illustrate this functionality.
|
||||
|
||||
.. prerequisites:: Prerequisites
|
||||
|
||||
- We assume that Rougail's library is :ref:`installed <installation>` on your computer.
|
||||
|
||||
- It is possible to retrieve the current state of the various Rougail files manipulated in this tutorial step
|
||||
by checking out the corresponding tag of the `rougail-tutorials` git repository.
|
||||
Each tag corresponds to a stage of progress in the tutorial.
|
||||
Of course, you can also decide to copy/paste or download the tutorial files contents while following the tutorial steps.
|
||||
|
||||
If you want to follow this tutorial with the help of the corresponding :tutorial:`rougail-tutorials git repository <src/branch/1.1>`,
|
||||
this workshop page corresponds to the tags :tutorial:`v1.1_040 <src/tag/v1.1_040/README.md>` to :tutorial:`v1.1_041 <src/tag/v1.1_041/README.md>`
|
||||
in the repository.
|
||||
|
||||
::
|
||||
|
||||
git clone https://forge.cloud.silique.fr/stove/rougail-tutorials.git
|
||||
git switch --detach v1.1_040
|
||||
|
||||
HTTPS family
|
||||
-------------
|
||||
|
||||
We have split the definition of the `manual` family into two specific files,
|
||||
the :file:`10-manual.yml` and the :file:`20-manual.yml` structure file:
|
||||
|
||||
.. raw:: html
|
||||
:class: output
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_040/tree.html
|
||||
|
||||
..
|
||||
<p>
|
||||
<a href="https://forge.cloud.silique.fr/stove/rougail-tutorials/src/commit/v1.1_040/./">.</a><br/>
|
||||
└── <a href="https://forge.cloud.silique.fr/stove/rougail-tutorials/src/commit/v1.1_040/./firefox/">firefox</a><br/>
|
||||
├── <a href="https://forge.cloud.silique.fr/stove/rougail-tutorials/src/commit/v1.1_040/./firefox/00-proxy.yml">00-proxy.yml</a><br/>
|
||||
├── <a href="https://forge.cloud.silique.fr/stove/rougail-tutorials/src/commit/v1.1_040/./firefox/10-manual.yml">10-manual.yml</a><br/>
|
||||
└── <a href="https://forge.cloud.silique.fr/stove/rougail-tutorials/src/commit/v1.1_040/./firefox/20-manual.yml">20-manual.yml</a><br/>
|
||||
<br/><br/></p>
|
||||
|
||||
We will continue to complete the :file:`20-manual.yml` structure file,
|
||||
with variables entirely equivalent to those found in the `http_proxy` family from the :file:`10-manual.yml` structure file.
|
||||
Until now, we only had the `use_for_https` :ref:`boolean variable in this structure file <tutorial_boolean_variable>`.
|
||||
Now we are going to define an address and a port in the `https_proxy` family:
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_040/firefox/20-manual.yml
|
||||
:linenos:
|
||||
:language: yaml
|
||||
:caption: The updated `manual` family in the :file:`firefox/20-manual.yml` structure file with the `https_proxy` family.
|
||||
|
||||
..
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
manual:
|
||||
|
||||
use_for_https: true # Also use this proxy for HTTPS
|
||||
|
||||
https_proxy: # HTTPS Proxy
|
||||
|
||||
address:
|
||||
description: HTTPS address
|
||||
type: domainname
|
||||
params:
|
||||
allow_ip: true
|
||||
|
||||
port:
|
||||
description: HTTPS Port
|
||||
type: port
|
||||
default: 8080
|
||||
|
||||
.. _tutorial_calc_variable:
|
||||
|
||||
A default value calculated from another variable
|
||||
--------------------------------------------------
|
||||
|
||||
.. type-along:: For those who follow the tutorial with the help of the git repository
|
||||
|
||||
Now you need to checkout the :tutorial:`v1.1_041 <src/tag/v1.1_041/README.md>` version::
|
||||
|
||||
git switch --detach v1.1_041
|
||||
|
||||
.. discussion:: A contextualized default value
|
||||
|
||||
A contextualized default value is a default value that changes according to the overall context of the configuration.
|
||||
A contextualized default value can come from, as we see here, a copy of the value of another variable.
|
||||
|
||||
The dynamic setting of a default value can be expressed this way: the default value is a pointer to another variable's value.
|
||||
Here, the defaut value of `manual.https_proxy.address` points to the value of `manual.http_proxy.address`.
|
||||
|
||||
This is the same thing for the default value of the `manual.https_proxy.port` variable,
|
||||
which points to the `manual.http_proxy.port` value.
|
||||
|
||||
.. note:: In the following we will see that the `manual.https_proxy.address` type is `domainname`.
|
||||
Indeed, this `domainname` type comes from the type of the variable it points to.
|
||||
|
||||
Reminder: here is the HTTP :file:`firefox/10-manual.yml` structure file:
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_041/firefox/10-manual.yml
|
||||
:linenos:
|
||||
:language: yaml
|
||||
:caption: The :file:`firefox/10-manual.yml` structure file with the `http_proxy` family and the `disabled` property
|
||||
|
||||
..
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
manual: # Manual proxy configuration
|
||||
|
||||
http_proxy: # HTTP Proxy
|
||||
|
||||
address:
|
||||
description: HTTP address
|
||||
type: domainname
|
||||
params:
|
||||
allow_ip: true
|
||||
|
||||
port:
|
||||
description: HTTP Port
|
||||
type: port
|
||||
default: 8080
|
||||
...
|
||||
|
||||
|
||||
And here is the :file:`firefox/20-manual.yml` structure file where the calculated default values are:
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_041/firefox/20-manual.yml
|
||||
:linenos:
|
||||
:language: yaml
|
||||
:caption: The :file:`firefox/20-manual.yml` structure file with the `hidden` property on the `https_proxy` family.
|
||||
|
||||
..
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
manual:
|
||||
|
||||
use_for_https: true # Also use this proxy for HTTPS
|
||||
|
||||
https_proxy: # HTTPS Proxy
|
||||
|
||||
address:
|
||||
description: HTTPS address
|
||||
default:
|
||||
variable: __.http_proxy.address
|
||||
|
||||
port:
|
||||
description: HTTPS Port
|
||||
default:
|
||||
variable: __.http_proxy.port
|
||||
...
|
||||
|
||||
We can see here that the `address` variable's default value is conditionned by the `__.http_proxy.address` variable's value.
|
||||
The target variable is `manual.http_proxy.address`.
|
||||
|
||||
.. seealso:: The `__.` is a :term:`relative path` notation and means the parent path of the current subfamily path.
|
||||
|
||||
In the python quasi algorithmic notation we could say that:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
__.http_proxy.address == http_proxy.address
|
||||
|
||||
This is true only because in our use case `http_proxy.address` is located
|
||||
in the same `manual` subfamiliy than `https_proxy.address`.
|
||||
|
||||
Have a look at the :ref:`variablepath` page for more details.
|
||||
|
||||
|
||||
We then say that the `manual.https_proxy.address` and the `manual.https_proxy.port` default values are *calculated*.
|
||||
|
||||
.. glossary::
|
||||
|
||||
calculated
|
||||
|
||||
We say that a variable's value or a default variable's value is calculated
|
||||
when there is a pointer which refers to another variable's value.
|
||||
|
||||
:ref:`Other types of calculations exists <calculated_variable>`, in which this type of behavior does not occur
|
||||
(the "pointer" behavior, notably type copying).
|
||||
|
||||
The other types of calculation we will be explained later in this tutorial.
|
||||
|
||||
We're going to load some :term:`user data <user data>` to see what happens:
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_041/config/01/config.yml
|
||||
:linenos:
|
||||
:language: yaml
|
||||
:caption: The :file:`config/01/config.yml` user data
|
||||
|
||||
..
|
||||
---
|
||||
proxy_mode: Manual proxy configuration
|
||||
manual:
|
||||
http_proxy:
|
||||
address: http.proxy.net
|
||||
port: 3128
|
||||
use_for_https: false
|
||||
https_proxy:
|
||||
address: https.proxy.net
|
||||
|
||||
Let's launch the Rougail CLI on it:
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_041/config/01/cmd_ro.txt
|
||||
:class: terminal
|
||||
|
||||
..
|
||||
rougail -m firefox/ -u yaml -yf config/01/config.yml
|
||||
|
||||
We have this result:
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_041/config/01/output_ro.html
|
||||
:class: output
|
||||
|
||||
..
|
||||
<pre>╭────────────── Caption ───────────────╮
|
||||
│ Variable <span style="color: #ffd700">Default value</span> │
|
||||
│ <span style="color: #00aa00">Modified value</span> │
|
||||
│ (⏳ Original default value) │
|
||||
╰──────────────────────────────────────╯
|
||||
Variables:
|
||||
<span style="color: #5c5cff">┣━━ </span>📓 proxy_mode (Configure Proxy Access to the Internet): <span style="color: #00aa00">Manual proxy </span>
|
||||
<span style="color: #5c5cff">┃ </span><span style="color: #00aa00">configuration</span> ◀ loaded from the YAML file "config/01/config.yml" (⏳ No
|
||||
<span style="color: #5c5cff">┃ </span>proxy)
|
||||
<span style="color: #5c5cff">┗━━ </span>📂 manual (Manual proxy configuration)
|
||||
<span style="color: #5c5cff"> </span><span style="color: #5c5cff">┣━━ </span>📂 http_proxy (HTTP Proxy)
|
||||
<span style="color: #5c5cff"> </span><span style="color: #5c5cff">┃ </span><span style="color: #5c5cff">┣━━ </span>📓 address (HTTP address): <span style="color: #00aa00">http.proxy.net</span> ◀ loaded from the YAML
|
||||
<span style="color: #5c5cff"> </span><span style="color: #5c5cff">┃ </span><span style="color: #5c5cff">┃ </span>file "config/01/config.yml"
|
||||
<span style="color: #5c5cff"> </span><span style="color: #5c5cff">┃ </span><span style="color: #5c5cff">┗━━ </span>📓 port (HTTP Port): <span style="color: #00aa00">3128</span> ◀ loaded from the YAML file
|
||||
<span style="color: #5c5cff"> </span><span style="color: #5c5cff">┃ </span><span style="color: #5c5cff"> </span>"config/01/config.yml" (⏳ 8080)
|
||||
<span style="color: #5c5cff"> </span><span style="color: #5c5cff">┣━━ </span>📓 use_for_https (Also use this proxy for HTTPS): <span style="color: #00aa00">false</span> ◀ loaded from
|
||||
<span style="color: #5c5cff"> </span><span style="color: #5c5cff">┃ </span>the YAML file "config/01/config.yml" (⏳ true)
|
||||
<span style="color: #5c5cff"> </span><span style="color: #5c5cff">┗━━ </span>📂 https_proxy (HTTPS Proxy)
|
||||
<span style="color: #5c5cff"> </span><span style="color: #5c5cff"> </span><span style="color: #5c5cff">┣━━ </span>📓 address (HTTPS address): <span style="color: #00aa00">https.proxy.net</span> ◀ loaded from the YAML
|
||||
<span style="color: #5c5cff"> </span><span style="color: #5c5cff"> </span><span style="color: #5c5cff">┃ </span>file "config/01/config.yml" (⏳ http.proxy.net)
|
||||
<span style="color: #5c5cff"> </span><span style="color: #5c5cff"> </span><span style="color: #5c5cff">┗━━ </span>📓 port (HTTPS Port): <span style="color: #ffd700">3128</span>
|
||||
</pre>
|
||||
|
||||
Notice that the default value is not changed when some values are settled from the :term:`user data file <user data>`.
|
||||
|
||||
The `https_proxy` variable's value is indeed modified, but the default value is still a calculated value (so the default value is indeed the value of the variable `http_proxy.address`, i.e., `"http.proxy.net"`), while the value defined by the user is `https.proxy.net`.
|
||||
|
||||
With the standard output of the Rougail CLI, the terminal display output, we can see the default value of the variable.
|
||||
|
||||
By interpreting the results of this standard output, we can see that even if a value has been assigned to this variable
|
||||
(meaning the default value is not used) the variable's default value is not changed, but rather its actual value.
|
||||
|
||||
.. keypoints:: Key points progress
|
||||
|
||||
**summary**
|
||||
|
||||
We have learned how to set the default value of the `https_proxy.address` variable
|
||||
with the value of the `http_proxy.address` variable. We did the same
|
||||
`https_proxy.port` and the `https_proxy.port` variables.
|
||||
|
||||
**notation**
|
||||
|
||||
We have learned a notation very usefull for the subfamilies traversal:
|
||||
|
||||
- the `_.` notation means the current path of the family you're currently in
|
||||
- the `__.` notation means the parent path of the current subfamily path.
|
||||
|
||||
Have a look at the :ref:`variablepath` page for more details.
|
||||
|
||||
224
docs/tutorial/choice.rst
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
.. _tutorial_choice:
|
||||
|
||||
A variable with possible values
|
||||
==================================
|
||||
|
||||
.. objectives:: Objectives
|
||||
|
||||
We will learn how to define variables with predefined available values.
|
||||
|
||||
.. prerequisites:: Prerequisites
|
||||
|
||||
- We assume that Rougail's library is :ref:`installed <installation>` on your computer.
|
||||
|
||||
- It is possible to retrieve the current state of the various Rougail files manipulated in this tutorial step
|
||||
by checking out the corresponding tag of the `rougail-tutorials` git repository.
|
||||
Each tag corresponds to a stage of progress in the tutorial.
|
||||
Of course, you can also decide to copy/paste or download the tutorial files contents while following the tutorial steps.
|
||||
|
||||
If you want to follow this tutorial with the help of the corresponding :tutorial:`rougail-tutorials git repository <src/branch/1.1>`,
|
||||
this workshop page corresponds to the tag :tutorial:`v1.1_010 <src/tag/v1.1_010/README.md>` in the repository:
|
||||
|
||||
::
|
||||
|
||||
git clone https://forge.cloud.silique.fr/stove/rougail-tutorials.git
|
||||
git switch --detach v1.1_010
|
||||
|
||||
A variable with a list of possible values
|
||||
---------------------------------------------
|
||||
|
||||
In the firefox browser, the proxy mode can be set by this way:
|
||||
|
||||
.. image:: images/firefox_02.png
|
||||
|
||||
A list of possible values for the `proxy_mode` variable is proposed.
|
||||
With Rougail there is the possibility of defining a list of available values
|
||||
with the `choices` variable's parameter:
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_010/firefox/00-proxy.yml
|
||||
:linenos:
|
||||
:language: yaml
|
||||
:caption: The `proxy_mode` variable with the `choice` parameter
|
||||
:name: RougailDictionaryChoiceType
|
||||
|
||||
..
|
||||
---
|
||||
proxy_mode:
|
||||
description: Configure Proxy Access to the Internet
|
||||
choices:
|
||||
- No proxy
|
||||
- Auto-detect proxy settings for this network
|
||||
- Use system proxy settings
|
||||
- Manual proxy configuration
|
||||
- Automatic proxy configuration URL
|
||||
default: No proxy
|
||||
|
||||
:tutorial:`Download this file from the rougail-tutorials git repository <src/tag/v1.1_010/firefox/00-proxy.yml>`
|
||||
|
||||
Let's run the Rougail CLI with these available values:
|
||||
|
||||
.. code-block:: text
|
||||
:class: terminal
|
||||
|
||||
rougail -m firefox/
|
||||
|
||||
We have an output like this one:
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_010/config/01/output_ro.html
|
||||
:class: output
|
||||
|
||||
..
|
||||
<pre>╭────────────────────────── Caption ──────────────────────────╮
|
||||
│ Variable <span style="color: #ffd700">Default value</span> │
|
||||
│ <span style="color: #5c5cff">Undocumented variable</span> Modified value │
|
||||
│ <span style="color: #ff0000">Undocumented but modified variable</span> (<span style="color: #00aa00">Original default value</span>) │
|
||||
│ <span style="color: #ffaf00">Unmodifiable variable</span> │
|
||||
╰─────────────────────────────────────────────────────────────╯
|
||||
Variables:
|
||||
<span style="color: #5c5cff">┗━━ </span>📓 proxy_mode: <span style="color: #ffd700">No proxy</span>
|
||||
</pre>
|
||||
|
||||
`No proxy` is an available variable's value. We say that the `proxy_mode` variable is *constrained*
|
||||
by the possibilities of the `choice` parameter.
|
||||
|
||||
.. type-along:: Let's add some user data to this structure
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_010/config/03/config.yml
|
||||
:linenos:
|
||||
:language: yaml
|
||||
:caption: A user data specification
|
||||
|
||||
:tutorial:`Download this file from the rougail-tutorials git repository <src/tag/v1.1_010/config/03/config.yml>`
|
||||
|
||||
If we run the Rougail CLI with this user data:
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_010/config/03/cmd_ro.txt
|
||||
:class: terminal
|
||||
|
||||
..
|
||||
rougail -m firefox/ -u yaml -yf config/03/config.yml
|
||||
|
||||
We have this output:
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_010/config/03/output_ro.html
|
||||
:class: output
|
||||
|
||||
..
|
||||
<pre>╭────────────── Caption ───────────────╮
|
||||
│ Variable Modified value │
|
||||
│ (<span style="color: #00aa00">⏳ Original default value</span>) │
|
||||
╰──────────────────────────────────────╯
|
||||
Variables:
|
||||
<span style="color: #5c5cff">┗━━ </span>📓 Configure Proxy Access to the Internet: Manual proxy configuration ◀ loaded from the YAML file "config/03/config.yml" (⏳ <span style="color: #00aa00">No proxy</span>)
|
||||
</pre>
|
||||
|
||||
As we set the `proxy_mode` variable from a user data file,
|
||||
we now have specified a value which is **not** a default value, and
|
||||
the output of the Rougail CLI explicitly shows that a user data value has been entered,
|
||||
it shows which user data file this value comes from, and it also indicates
|
||||
what the default value is for information purposes.
|
||||
|
||||
.. type-along:: The constraints that come with the choices
|
||||
|
||||
The `proxy_mode` variable's possible values is *constrained*.
|
||||
|
||||
We have the list of the possible (authorized) values:
|
||||
|
||||
- `No proxy`
|
||||
- `Auto-detect proxy settings for this network`
|
||||
- `Use system proxy settings`
|
||||
- `Manual proxy configuration`
|
||||
- `Automatic proxy configuration URL`
|
||||
|
||||
.. questions:: Question
|
||||
|
||||
What happens if I set a value that is not available in the choices?
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_010/config/04/config.yml
|
||||
:linenos:
|
||||
:language: yaml
|
||||
:caption: A (false) user data specification
|
||||
|
||||
:tutorial:`Download this file from the rougail-tutorials git repository <src/tag/v1.1_010/config/04/config.yml>`
|
||||
|
||||
If we run the Rougail CLI with this user data:
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_010/config/04/cmd_ro.txt
|
||||
:class: terminal
|
||||
|
||||
..
|
||||
rougail -m firefox/ -u yaml -yf config/03/config.yml
|
||||
|
||||
We have this output:
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_010/config/04/output_ro.html
|
||||
:class: output
|
||||
|
||||
We can see here that Rougail warns us about an invalid value that is not in the available choices,
|
||||
that's why this value will not be used and it falls back to the original default value.
|
||||
|
||||
But maybe this is not the behavior you need. Maybe you need to stop everything if Rougail detects that
|
||||
something is going wrong, maybe you need some kind of a strict mode.
|
||||
|
||||
Indeed, this warning can be transformed into an error.
|
||||
|
||||
If we run the Rougail CLI with this `--cli.invalid_user_data_error` parameter:
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_010/config/04/cmd_invalid.txt
|
||||
:class: terminal
|
||||
|
||||
..
|
||||
rougail -m firefox/ -u yaml -yf config/03/config.yml --cli.invalid_user_data_error
|
||||
|
||||
Then we have an `error` output instead of a `warning` output:
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_010/config/04/output_invalid.html
|
||||
:class: output
|
||||
|
||||
..
|
||||
<pre><span style="font-weight: bold; color: #ff0000">🛑 ERRORS</span>
|
||||
<span style="color: #ff0000">┗━━ </span>the value "foo" is an invalid choice for "proxy_mode" (Configure Proxy Access to the Internet), only "Auto-detect proxy settings for this network", "Automatic proxy configuration URL", "Manual proxy
|
||||
<span style="color: #ff0000"> </span>configuration", "No proxy" and "Use system proxy settings" are allowed, it will be ignored when loading from the YAML file "config/04/config.yml"
|
||||
</pre>
|
||||
|
||||
|
||||
|
||||
.. keypoints:: Key points progress
|
||||
|
||||
Indeed, in the Firefox configuration, it is possible to define several configuration modes,
|
||||
from no proxy at all to different kind of automatic or manual configuration modes.
|
||||
The choices, the list of available values for a variable, can help us to handle this situation.
|
||||
|
||||
**Progress**
|
||||
|
||||
To sum up, we have arrived at this point in writing a structure file like this:
|
||||
|
||||
**Structure description file**
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_010/firefox/00-proxy.yml
|
||||
:linenos:
|
||||
:language: yaml
|
||||
:caption: A Rougail structure file with a variable named `proxy_mode`, with a default value.
|
||||
|
||||
..
|
||||
|
||||
.. raw:: text
|
||||
|
||||
---
|
||||
proxy_mode:
|
||||
description: Configure Proxy Access to the Internet
|
||||
choices:
|
||||
- No proxy
|
||||
- Auto-detect proxy settings for this network
|
||||
- Use system proxy settings
|
||||
- Manual proxy configuration
|
||||
- Automatic proxy configuration URL
|
||||
default: No proxy
|
||||
|
||||
558
docs/tutorial/customtype.rst
Normal file
|
|
@ -0,0 +1,558 @@
|
|||
.. _tutorial_custom_type:
|
||||
|
||||
Custom type
|
||||
============
|
||||
|
||||
.. objectives:: Objectives
|
||||
|
||||
In this sections we are going to learn how to create custom types with Rougail.
|
||||
In short, a custom type is nothing more than a kind of a template for a variable or a family.
|
||||
|
||||
.. prerequisites:: Prerequisites
|
||||
|
||||
- We assume that Rougail's library is :ref:`installed <installation>` on your computer.
|
||||
|
||||
- It is possible to retrieve the current state of the various Rougail files manipulated in this tutorial step
|
||||
by checking out the corresponding tag of the `rougail-tutorials` git repository.
|
||||
Each tag corresponds to a stage of progress in the tutorial.
|
||||
Of course, you can also decide to copy/paste or download the tutorial files contents while following the tutorial steps.
|
||||
|
||||
If you want to follow this tutorial with the help of the corresponding :tutorial:`rougail-tutorials git repository <src/branch/1.1>`,
|
||||
this workshop page corresponds to the tags :tutorial:`v1.1_080 <src/tag/v1.1_080/README.md>` to :tutorial:`v1.1_085 <src/tag/v1.1_085/README.md>`
|
||||
in the repository.
|
||||
|
||||
::
|
||||
|
||||
git clone https://forge.cloud.silique.fr/stove/rougail-tutorials.git
|
||||
git switch --detach v1.1_080
|
||||
|
||||
HTTP Proxy with "proxy" type
|
||||
--------------------------------
|
||||
|
||||
Let's look now at the possibilities for adding types.
|
||||
This feature is essential for having a truly adaptable tool.
|
||||
|
||||
.. note:: It is actually possible to add types,
|
||||
but that involves adding predefined types to the :term:`Tiramisu` underlying consistency library itself,
|
||||
and that’s a different matter altogether. There is a simpler way to achieve this with the Rougail type definition feature.
|
||||
|
||||
It is possible in Rougail to create custom types in a very simple way, it is much like defining variables or families.
|
||||
|
||||
Our folder structure will be expanded a bit:
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_080/tree.html
|
||||
|
||||
Notice that we have now a new :file:`types` folder in our tree structure.
|
||||
This is where we will place our new `proxy` type definition.
|
||||
|
||||
.. note:: Choosing the :file:`types/proxy/00-type.yml` file name is not mandatory.
|
||||
You can name this folder whatever you want.
|
||||
It is simply a good practice to separate structure files from type definition files.
|
||||
We will see later on how to indicate to Rougail that a file contains a type declaration.
|
||||
|
||||
In accordance with our :ref:`naming policy <namingconvention>`, we have created a file named :file:`00-type.yml`
|
||||
inside the `proxy` folder.
|
||||
Let's examine this more closely this :file:`types/proxy/00-type.yml` type definition file:
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_080/types/proxy/00-type.yml
|
||||
:language: yaml
|
||||
:caption: The :file:`types/proxy/00-type.yml` type structure file that defines our new `proxy` type.
|
||||
|
||||
..
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
proxy:
|
||||
|
||||
address:
|
||||
description: Proxy address
|
||||
type: domainname
|
||||
params:
|
||||
allow_ip: true
|
||||
|
||||
port:
|
||||
description: Proxy port
|
||||
type: port
|
||||
default: 8080
|
||||
...
|
||||
|
||||
The new type named `proxy` is declared the same way we declare a family.
|
||||
It's more or less like a family declaration except it will be used as a type definition.
|
||||
If you remember, it's mostly the content as the family `manual.http_proxy` in `firefox/10-manual.yml` file of this tutorial.
|
||||
|
||||
.. questions:: How do we use a new type?
|
||||
|
||||
Very simply. In the usual way: we will add a `type` parameter in our family declaration.
|
||||
|
||||
Let's modify the existing family using this new `proxy` type:
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_080/firefox/10-manual.yml
|
||||
:language: yaml
|
||||
:caption: The :file:`firefox/10-manual.yml` structure file with less code due to the `proxy` type definition
|
||||
|
||||
..
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
manual:
|
||||
description: Manual proxy configuration
|
||||
disabled:
|
||||
variable: _.proxy_mode
|
||||
when_not: Manual proxy configuration
|
||||
|
||||
http_proxy:
|
||||
description: HTTP Proxy
|
||||
type: proxy
|
||||
...
|
||||
|
||||
We can see that the type declared for the `http_proxy` family is now `type: proxy`.
|
||||
It's perfectly natural in the Rougail style.
|
||||
|
||||
Due to the type definition we can "omit" some settings in the structure file
|
||||
such as the `domainname` type and the `allow_ip` parameter.
|
||||
And the `address` variable it is not necessary to be specified at all in the structure file
|
||||
because it's in the type definition.
|
||||
|
||||
In order to use our new type we need to declare it to Rougail otherwise the new type is not available.
|
||||
The Rougail CLI has the `--types` type declaration command line option for this purpose.
|
||||
Let's launch the Rougail CLI with this command line parameter:
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_080/config/01/cmd_ro.txt
|
||||
:class: terminal
|
||||
|
||||
The CLI output is entirely standard and does not specifically mention the call to a new type.
|
||||
The result is the same as usual, as if the type declaration were omitted, which is what we want.
|
||||
We want the same behavior as usual.
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_080/config/01/output_ro.html
|
||||
:class: output
|
||||
|
||||
HTTPS and SOCKS Proxy with "proxy" type
|
||||
---------------------------------------
|
||||
|
||||
.. type-along:: For those who follow the tutorial with the help of the git repository
|
||||
|
||||
Now you need to checkout the :tutorial:`v1.1_081 <src/tag/v1.1_081/README.md>` version:
|
||||
|
||||
git switch --detach v1.1_081
|
||||
|
||||
With this use of a type, it is possible to define our HTTPS and SOCKS Proxy in a much more conscious way:
|
||||
It's very practical. In fact, the type definition adds nothing else to the structural logic.
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_081/firefox/20-manual.yml
|
||||
:language: yaml
|
||||
:caption: The :file:`firefox/20-manual.yml` structure file with less code due to the `proxy` type definition
|
||||
|
||||
..
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
manual:
|
||||
|
||||
use_for_https: true # Also use this proxy for HTTPS
|
||||
|
||||
https_proxy:
|
||||
description: HTTPS Proxy
|
||||
type: proxy
|
||||
hidden:
|
||||
variable: _.use_for_https
|
||||
|
||||
socks_proxy:
|
||||
description: SOCKS Proxy
|
||||
type: proxy
|
||||
...
|
||||
|
||||
Now we have two families with the `proxy` type: `https_proxy` and `socks_proxy`.
|
||||
|
||||
But we haven't recovered everything we had before.
|
||||
Using a type definition is fine, but we still need to find exactly the configuration situation
|
||||
we had before using the type definition.
|
||||
|
||||
Add a variable in a family with custom type
|
||||
--------------------------------------------
|
||||
|
||||
.. type-along:: For those who follow the tutorial with the help of the git repository
|
||||
|
||||
Now you need to checkout the :tutorial:`v1.1_082 <src/tag/v1.1_082/README.md>` version::
|
||||
|
||||
git switch --detach v1.1_082
|
||||
|
||||
|
||||
In the `socks_proxy` family definition, we need to added a new variable, the `version` variable:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
version:
|
||||
description: SOCKS host version used by proxy
|
||||
choices:
|
||||
- v4
|
||||
- v5
|
||||
default: v5
|
||||
|
||||
You can see that what we call a type definition in Rougail is very flexible, because it is perfectly possible
|
||||
to add to what has been defined in the type.
|
||||
The type definition here is therefore not only a template but much more an extensible schema.
|
||||
|
||||
Redefine default value in custom type variable
|
||||
-----------------------------------------------
|
||||
|
||||
.. type-along:: For those who follow the tutorial with the help of the git repository
|
||||
|
||||
Now you need to checkout the :tutorial:`v1.1_083 <src/tag/v1.1_083/README.md>` version::
|
||||
|
||||
git switch --detach v1.1_083
|
||||
|
||||
In this section we are going to make an implicit :ref:`redefinition <redefine>` of variables default values.
|
||||
|
||||
.. note::
|
||||
|
||||
We've always said that the redefine is explicit. But there's an exception here.
|
||||
There are two types of redefine for a custom type, an implicit and an explicit.
|
||||
An implicit redefinition is a redefinition which has not been declared with the `redefine` attribute.
|
||||
An explicit redefinition is a redefinition which has been declared with the `redefine: true` attribute.
|
||||
|
||||
Only default values can be implicitly redefined (and only in the type definitions), all other attributes
|
||||
need to be explicitely redefined.
|
||||
|
||||
In the type definition file, we are now setting default values for the `address` and `port` variables:
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_083/types/proxy/00-type.yml
|
||||
:language: yaml
|
||||
:caption: The :file:`types/proxy/00-type.yml` type definition file with the default values for `address` and `port`
|
||||
|
||||
..
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
proxy:
|
||||
|
||||
address:
|
||||
description: Proxy address
|
||||
type: domainname
|
||||
params:
|
||||
allow_ip: true
|
||||
default:
|
||||
variable: __.http_proxy.address
|
||||
|
||||
port:
|
||||
description: Proxy port
|
||||
type: port
|
||||
default:
|
||||
variable: __.http_proxy.port
|
||||
...
|
||||
|
||||
But we don't want theses default values for HTTP definition. We can :term:`redefine` these type settings in the structure file:
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_083/firefox/10-manual.yml
|
||||
:language: yaml
|
||||
:caption: The :file:`firefox/10-manual.yml` structure definition file with the **redefined** default values for `address` and `port`
|
||||
|
||||
..
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
manual:
|
||||
description: Manual proxy configuration
|
||||
disabled:
|
||||
variable: _.proxy_mode
|
||||
when_not: Manual proxy configuration
|
||||
|
||||
http_proxy:
|
||||
description: HTTP Proxy
|
||||
type: proxy
|
||||
|
||||
address:
|
||||
default: null
|
||||
|
||||
port:
|
||||
default: 8080
|
||||
...
|
||||
|
||||
This means that the default values for these variables will now be those defined
|
||||
in the structure file if the values are defined (and not in the type definitions file).
|
||||
|
||||
Let's have a closer look at the behavior here.
|
||||
|
||||
Let's launch the Rougail CLI:
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_082/config/01/cmd_ro.txt
|
||||
:class: terminal
|
||||
|
||||
..
|
||||
rougail -m firefox/ -u yaml -yf config/01/config.yml
|
||||
|
||||
We have this output:
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_082/config/01/output_ro.html
|
||||
:class: output
|
||||
|
||||
We can see in the output that
|
||||
|
||||
- the default values of the `port` variable, which is `8080` in the structure file, comes from the strucure file.
|
||||
- the default values of the `address` variable is not set because it is `null` by default in the structure file,
|
||||
so there is not such thing as a default value set for this variable.
|
||||
|
||||
.. questions:: What happens if the default value in the type definition is not suitable for us?
|
||||
|
||||
If we hadn't defined a value in the userdata file, the Rougail CLI would have returned the following error:
|
||||
|
||||
::
|
||||
|
||||
🛑 Caution
|
||||
┗━━ Manual proxy configuration
|
||||
┣━━ HTTP Proxy
|
||||
┃ ┗━━ Proxy address: 🛑 mandatory variable but has no value
|
||||
┗━━ SOCKS Proxy
|
||||
┗━━ Proxy address: 🛑 mandatory variable but has no value
|
||||
|
||||
Therefore, the default value that was taken into account is indeed that of the structure file, and not that of the type definition.
|
||||
|
||||
.. note:: We can see that the Rougail behavior is always very simple, there is no such thing as an MRO
|
||||
(Method Resolution Object) that try fallback to the default value defined in the type definition file.
|
||||
The Rougail behavior is much more simple and transparent.
|
||||
|
||||
.. type-along:: kinematics of setting the `address` value
|
||||
|
||||
Let's take the time to explain how the value of the variable `manual.http_proxy.address` is determined using the type definition.
|
||||
|
||||
The :file:`10-manual.yml` structure file defines the :file:`manual.http_proxy` family
|
||||
which is defined with the help of the `proxy` type:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
http_proxy:
|
||||
description: HTTP Proxy
|
||||
type: proxy
|
||||
|
||||
In the :file:`types/proxy/00-type.yml` file we have the `proxy` type definition and its default value setting:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
default:
|
||||
variable: __.http_proxy.address
|
||||
|
||||
This default value setting point to the `http_proxy.address` value in the :file:`firefox/10-manual.yml` structure file:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
address:
|
||||
default: null
|
||||
|
||||
Which is `null` by default but in the :file:`config/01/config.yml` user data file we have the `http.proxy.net` value set:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
manual:
|
||||
http_proxy:
|
||||
address: http.proxy.net
|
||||
|
||||
In the CLI standard output we can see that the `http_proxy.address` variable value is
|
||||
finally set by the user data file:
|
||||
|
||||
::
|
||||
|
||||
┗━━ 📂 manual (Manual proxy configuration)
|
||||
┣━━ 📂 http_proxy (HTTP Proxy)
|
||||
┃ ┣━━ 📓 address (Proxy address): http.proxy.net ◀ loaded from the YAML
|
||||
┃ ┃ file "config/01/config.yml"
|
||||
|
||||
|
||||
Redefine other parameter in custom type for HTTP
|
||||
--------------------------------------------------
|
||||
|
||||
.. type-along:: For those who follow the tutorial with the help of the git repository
|
||||
|
||||
Now you need to checkout the :tutorial:`v1.1_084 <src/tag/v1.1_084/README.md>` version::
|
||||
|
||||
git switch --detach v1.1_084
|
||||
|
||||
In this sections we are going to make explicit :term:`redefinitions <redefine>`.
|
||||
|
||||
Note here that, in order to allow for the genericity of a type declaration,
|
||||
we have omitted to specify the variable descriptions in the type declaration.
|
||||
We will therefore need to enter these descriptions in the structure file.
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_084/types/proxy/00-type.yml
|
||||
:language: yaml
|
||||
:caption: The :file:`types/proxy/00-type.yml` type definition file with the default definitions and no description
|
||||
|
||||
..
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
proxy:
|
||||
|
||||
address:
|
||||
type: domainname
|
||||
params:
|
||||
allow_ip: true
|
||||
default:
|
||||
variable: __.http_proxy.address
|
||||
|
||||
port:
|
||||
type: port
|
||||
default:
|
||||
variable: __.http_proxy.port
|
||||
...
|
||||
|
||||
So, as the `address` and `port` variables don't have any `description` attribute,
|
||||
we need to add one. It is something like an extension of the type definitions here
|
||||
in the structure file:
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_084/firefox/10-manual.yml
|
||||
:language: yaml
|
||||
:caption: The :file:`firefox/10-manual.yml` structure definition file with explicit redefinitions
|
||||
|
||||
..
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
manual:
|
||||
description: Manual proxy configuration
|
||||
disabled:
|
||||
variable: _.proxy_mode
|
||||
when_not: Manual proxy configuration
|
||||
|
||||
http_proxy:
|
||||
description: HTTP Proxy
|
||||
type: proxy
|
||||
|
||||
address:
|
||||
redefine: true
|
||||
default: null
|
||||
description: HTTP proxy address
|
||||
|
||||
port:
|
||||
redefine: true
|
||||
default: 8080
|
||||
description: HTTP proxy port
|
||||
...
|
||||
|
||||
.. note:: Transforming an implicit defintion into an explicit redefinition is very simple; you just need to add the `redefine: true` attribute:
|
||||
|
||||
Let's launch the Rougail CLI:
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_083/config/01/cmd_ro.txt
|
||||
:class: terminal
|
||||
|
||||
..
|
||||
rougail -m firefox/ -u yaml -yf config/01/config.yml
|
||||
|
||||
We have this output:
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_083/config/01/output_ro.html
|
||||
:class: output
|
||||
|
||||
..
|
||||
Variables:
|
||||
┣━━ 📓 Configure Proxy Access to the Internet: Manual proxy configuration ◀
|
||||
┃ loaded from the YAML file "config/01/config.yml" (⏳ No proxy)
|
||||
┗━━ 📂 Manual proxy configuration
|
||||
┣━━ 📂 HTTP Proxy
|
||||
┃ ┣━━ 📓 HTTP proxy address: http.proxy.net ◀ loaded from the YAML file
|
||||
┃ ┃ "config/01/config.yml"
|
||||
┃ ┗━━ 📓 HTTP proxy port: 3128 ◀ loaded from the YAML file
|
||||
┃ "config/01/config.yml" (⏳ 8080)
|
||||
┣━━ 📓 Also use this proxy for HTTPS: false ◀ loaded from the YAML file
|
||||
┃ "config/01/config.yml" (⏳ true)
|
||||
┣━━ 📂 HTTPS Proxy
|
||||
┃ ┣━━ 📓 HTTPS proxy address: https.proxy.net ◀ loaded from the YAML file
|
||||
┃ ┃ "config/01/config.yml" (⏳ http.proxy.net)
|
||||
┃ ┗━━ 📓 HTTPS proxy port: 3128
|
||||
┗━━ 📂 SOCKS Proxy
|
||||
┣━━ 📓 SOCKS proxy address: http.proxy.net
|
||||
┣━━ 📓 SOCKS proxy port: 3128
|
||||
┗━━ 📓 SOCKS host version used by proxy: v5
|
||||
|
||||
We can see in the output that the `address` and `port` variables have default values,
|
||||
and descriptions ("HTTP proxy address", "HTTP proxy port") that weren't present in the
|
||||
type definition file.
|
||||
|
||||
Redefine other parameter in custom type for HTTPS and SOCKS
|
||||
-----------------------------------------------------------
|
||||
|
||||
.. type-along:: For those who follow the tutorial with the help of the git repository
|
||||
|
||||
Now you need to checkout the :tutorial:`v1.1_085 <src/tag/v1.1_085/README.md>` version::
|
||||
|
||||
git switch --detach v1.1_085
|
||||
|
||||
We're going to do exactly the same modification with the `socks_proxy` family,
|
||||
that is we will base the `socks_proxy` family on the type definition.
|
||||
|
||||
Following the same reasoning, we add a in the structure file some `description` attributes to the `socks_proxy` family
|
||||
and also add some explicit redefinition attribute (`redefine: true`).
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_085/firefox/20-manual.yml
|
||||
:language: yaml
|
||||
:caption: The :file:`firefox/20-manual.yml` structure file with the `redefine` and the `description` attribute
|
||||
|
||||
..
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
manual:
|
||||
|
||||
use_for_https: true # Also use this proxy for HTTPS
|
||||
|
||||
https_proxy:
|
||||
description: HTTPS Proxy
|
||||
type: proxy
|
||||
hidden:
|
||||
variable: _.use_for_https
|
||||
|
||||
address:
|
||||
redefine: true
|
||||
description: HTTPS proxy address
|
||||
|
||||
port:
|
||||
redefine: true
|
||||
description: HTTPS proxy port
|
||||
|
||||
socks_proxy:
|
||||
description: SOCKS Proxy
|
||||
type: proxy
|
||||
|
||||
address:
|
||||
redefine: true
|
||||
description: SOCKS proxy address
|
||||
|
||||
port:
|
||||
redefine: true
|
||||
description: SOCKS proxy port
|
||||
|
||||
version:
|
||||
description: SOCKS host version used by proxy
|
||||
choices:
|
||||
- v4
|
||||
- v5
|
||||
default: v5
|
||||
...
|
||||
|
||||
|
||||
.. keypoints:: Key points
|
||||
|
||||
- the very practical aspects of type declaration
|
||||
- type usage in the Rougail CLI
|
||||
- more conscious family definition
|
||||
- using a type for an extended family definition
|
||||
- we can redefine things in the structure file and it overloads the type definition file
|
||||
- implicit or explicit redefinitions
|
||||
|
||||
We have seen how the definition of type, used effectively, allows for a new expressiveness.
|
||||
|
||||
259
docs/tutorial/document.rst
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
A full documented variable
|
||||
==============================
|
||||
|
||||
.. objectives:: Objectives
|
||||
|
||||
You’ve no doubt wondered, on more than one occasion, how to do this or that;
|
||||
even if you have the documentation, it’s not clear enough.
|
||||
|
||||
What would make it clear is a good example.
|
||||
|
||||
With Rougail, you can add examples into the structural specifications of a variable or a family, illustrative examples.
|
||||
That is what we will look at in this section. Documentation through examples.
|
||||
|
||||
.. prerequisites:: Prerequisites
|
||||
|
||||
- We assume that Rougail's library is :ref:`installed <installation>` on your computer.
|
||||
|
||||
- It is possible to retrieve the current state of the various Rougail files manipulated in this tutorial step
|
||||
by checking out the corresponding tag of the `rougail-tutorials` git repository.
|
||||
Each tag corresponds to a stage of progress in the tutorial.
|
||||
Of course, you can also decide to copy/paste or download the tutorial files contents while following the tutorial steps.
|
||||
|
||||
If you want to follow this tutorial with the help of the corresponding :tutorial:`rougail-tutorials git repository <src/branch/1.1>`,
|
||||
this workshop page corresponds to the tags :tutorial:`v1.1_120 <src/tag/v1.1_120/README.md>` to :tutorial:`v1.1_121 <src/tag/v1.1_121/README.md>`
|
||||
in the repository.
|
||||
|
||||
::
|
||||
|
||||
git clone https://forge.cloud.silique.fr/stove/rougail-tutorials.git
|
||||
git switch --detach v1.1_120
|
||||
|
||||
|
||||
Examples
|
||||
-----------
|
||||
|
||||
How to define example usage? All you need to do is add an `examples` parameter to the structural definition of your variable.
|
||||
Let's give some usage examples of how to use our `no_proxy` variable:
|
||||
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_120/firefox/40-no_proxy.yml
|
||||
:language: yaml
|
||||
:caption: The :file:`firefox/40-no_proxy` structure definition file with an `example` parameter
|
||||
|
||||
..
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
no_proxy:
|
||||
description: Address for which proxy will be desactivated
|
||||
examples:
|
||||
- .mozilla.org
|
||||
- .net.nz
|
||||
- 192.168.1.0/24
|
||||
type: domainname
|
||||
params:
|
||||
allow_ip: true
|
||||
allow_cidr_network: true
|
||||
allow_without_dot: true
|
||||
allow_startswith_dot: true
|
||||
multi: true
|
||||
mandatory: false
|
||||
disabled:
|
||||
variable: _.proxy_mode
|
||||
when: No proxy
|
||||
...
|
||||
|
||||
.. attention:: Note: the `examples` parameter does not specify default values. **It's just examples, it's not a setting**.
|
||||
|
||||
If we launch the Rougail CLI on user data:
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_120/config/03/config.yml
|
||||
:language: yaml
|
||||
:caption: The :file:`config/03/config.yml` user data file with an `example` parameter but no value set
|
||||
|
||||
..
|
||||
---
|
||||
proxy_mode: Automatic proxy configuration URL
|
||||
auto: https://auto.proxy.net/wpad.dat
|
||||
|
||||
we can see that the `no_proxy` variable has no user data settings.
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_120/config/03/cmd_ro.txt
|
||||
:class: terminal
|
||||
|
||||
..
|
||||
rougail -m firefox/ --types types/proxy -u yaml -yf config/01/config.yml
|
||||
|
||||
We do indeed obtain the value empty list `[]` for the `no_proxy` variable:
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_120/config/03/output_ro.html
|
||||
:class: output
|
||||
|
||||
..
|
||||
╭────────────── Caption ───────────────╮
|
||||
│ Variable Default value │
|
||||
│ Modified value │
|
||||
│ (⏳ Original default value) │
|
||||
╰──────────────────────────────────────╯
|
||||
Variables:
|
||||
┣━━ 📓 Configure Proxy Access to the Internet: Automatic proxy configuration URL ◀ loaded from the YAML file "config/03/config.yml"
|
||||
┃ (⏳ No proxy)
|
||||
┣━━ 📓 Automatic proxy configuration URL: https://auto.proxy.net/wpad.dat ◀ loaded from the YAML file "config/03/config.yml"
|
||||
┗━━ 📓 Address for which proxy will be desactivated: []
|
||||
|
||||
.. type-along:: If we set some user data values
|
||||
|
||||
Just to be thorough, let's look at what happens in a case where there is a value for `no_proxy` entered in the user data file:
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_120/config/02/config.yml
|
||||
:language: yaml
|
||||
:caption: The :file:`config/03/config.yml` user data file with some value set
|
||||
|
||||
We launch the Rougail CLI:
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_120/config/02/cmd_ro.txt
|
||||
:class: terminal
|
||||
|
||||
..
|
||||
rougail -m firefox/ --types types/proxy -u yaml -yf config/02/config.yml
|
||||
|
||||
And we have the `no_proxy`'s expected value. No trace in the output of the examples settings of the variable:
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_120/config/02/output_ro.html
|
||||
:class: output
|
||||
|
||||
..
|
||||
╭────────────── Caption ───────────────╮
|
||||
│ Variable Modified value │
|
||||
│ (⏳ Original default value) │
|
||||
╰──────────────────────────────────────╯
|
||||
Variables:
|
||||
┣━━ 📓 Configure Proxy Access to the Internet: Automatic proxy configuration URL
|
||||
┃ ◀ loaded from the YAML file "config/02/config.yml" (⏳ No proxy)
|
||||
┣━━ 📓 Automatic proxy configuration URL: https://auto.proxy.net/wpad.dat ◀
|
||||
┃ loaded from the YAML file "config/02/config.yml"
|
||||
┗━━ 📓 Address for which proxy will be desactivated:
|
||||
┣━━ example.net ◀ loaded from the YAML file "config/02/config.yml"
|
||||
┗━━ 192.168.1.0/24 ◀ loaded from the YAML file "config/02/config.yml"
|
||||
|
||||
In all cases, we can see that none of the values cited in the examples (`.mozilla.org`, `.net.nz`) appear.
|
||||
|
||||
|
||||
.. type-along:: In that case, is there a use for these examples?
|
||||
|
||||
This examples parameter is useful when generating variable documentation. That's where the examples appear.
|
||||
|
||||
If we launch the Rougail CLI for the documentation generation:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
rougail -m firefox --types types/proxy -o doc --doc.output_format html
|
||||
|
||||
We have this output:
|
||||
|
||||
.. raw:: html
|
||||
:class: output
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Variable </th><th>Description </th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td><b>auto</b><br/><mark><a href='https://rougail.readthedocs.io/en/latest/variable.html#variables-types'>web address</a></mark> <mark>mandatory</mark> <mark><i>disabled</i></mark> </td><td>Automatic proxy configuration URL.<br/><b>Validators</b>: <ul><li>well-known ports (1 to 1023) are allowed</li>
|
||||
<li>registred ports (1024 to 49151) are allowed</li>
|
||||
<li>type domainname</li>
|
||||
<li>the domain name can be a hostname</li></ul><br/><b>Disabled</b>: when the variable "proxy_mode" hasn't the value "Automatic proxy configuration URL" </td></tr>
|
||||
<tr><td><b>no_proxy</b><br/><mark><a href='https://rougail.readthedocs.io/en/latest/variable.html#variables-types'>domainname</a></mark> <mark>multiple</mark> <mark><i>disabled</i></mark> <mark>unique</mark></td><td>Address for which proxy will be desactivated.<br/><b>Validators</b>: <ul><li>type domainname</li>
|
||||
<li>the domain name can starts by a dot</li>
|
||||
<li>the domain name can be a hostname</li>
|
||||
<li>the domain name can be an IP</li>
|
||||
<li>the domain name can be network in CIDR format</li></ul><br/><b>Examples</b>: <ul><li>.mozilla.org</li>
|
||||
<li>.net.nz</li>
|
||||
<li>192.168.1.0/24</li></ul><br/><b>Disabled</b>: when the variable "proxy_mode" has the value "No proxy" </td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
..
|
||||
├─────────────────────────────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ no_proxy │ Address for which proxy will be desactivated. │
|
||||
│ domainname multiple disabled unique │ Validators: │
|
||||
│ │ • type domainname │
|
||||
│ │ • the domain name can starts by a dot │
|
||||
│ │ • the domain name can be a hostname │
|
||||
│ │ • the domain name can be an IP │
|
||||
│ │ • the domain name can be network in CIDR format │
|
||||
│ │ Examples: │
|
||||
│ │ • .mozilla.org │
|
||||
│ │ • .net.nz │
|
||||
│ │ • 192.168.1.0/24 │
|
||||
│ │ Disabled: when the variable "proxy_mode" has the value "No proxy" │
|
||||
└─────────────────────────────────────────────────────────────────────────────────────────────┴──────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
we can see that this time the examples (`.mozilla.org`, `.net.nz`) appear.
|
||||
|
||||
Help
|
||||
-------
|
||||
|
||||
.. type-along:: For those who follow the tutorial with the help of the git repository
|
||||
|
||||
Now you need to checkout the :tutorial:`v1.1_121 <src/tag/v1.1_121/README.md>` version::
|
||||
|
||||
git switch --detach v1.1_121
|
||||
|
||||
Could we define personalized assistance, in the same way that we defined examples?
|
||||
|
||||
Yes, very simply: we add a `help` parameter to our `no_proxy` variable:
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_121/firefox/40-no_proxy.yml
|
||||
:language: yaml
|
||||
:caption: The :file:`firefox/40-no_proxy` structure definition file with an `example` parameter
|
||||
|
||||
|
||||
In the same way, this help `"Connections to localhost, 127.0.0.1/8 and ::1 are never proxied"` will appear in the documentation:
|
||||
|
||||
.. raw:: html
|
||||
:class: output
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Variable </th><th>Description </th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td><b>auto</b><br/><mark><a href='https://rougail.readthedocs.io/en/latest/variable.html#variables-types'>web address</a></mark> <mark>mandatory</mark> <mark><i>disabled</i></mark> </td><td>Automatic proxy configuration URL.<br/><b>Validators</b>: <ul><li>well-known ports (1 to 1023) are allowed</li>
|
||||
<li>registred ports (1024 to 49151) are allowed</li>
|
||||
<li>type domainname</li>
|
||||
<li>the domain name can be a hostname</li></ul><br/><b>Disabled</b>: when the variable "proxy_mode" hasn't the value "Automatic proxy configuration URL" </td></tr>
|
||||
<tr><td><b>no_proxy</b><br/><mark><a href='https://rougail.readthedocs.io/en/latest/variable.html#variables-types'>domainname</a></mark> <mark>multiple</mark> <mark><i>disabled</i></mark> <mark>unique</mark></td><td>Address for which proxy will be desactivated.<br/>Connections to localhost, 127.0.0.1/8 and ::1 are never proxied.<br/><b>Validators</b>: <ul><li>type domainname</li>
|
||||
<li>the domain name can starts by a dot</li>
|
||||
<li>the domain name can be a hostname</li>
|
||||
<li>the domain name can be an IP</li>
|
||||
<li>the domain name can be network in CIDR format</li></ul><br/><b>Examples</b>: <ul><li>.mozilla.org</li>
|
||||
<li>.net.nz</li>
|
||||
<li>192.168.1.0/24</li></ul><br/><b>Disabled</b>: when the variable "proxy_mode" has the value "No proxy" </td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
.. type-along:: The difference between the `description` parameter and the `help` parameter
|
||||
|
||||
The help section serves as supplementary documentation regarding the description parameter.
|
||||
Please do not mix the :term:`description` parameter and the :term:`help` parameter's variable usage.
|
||||
|
||||
A :term:`description` allows you to describe the expected value(s) of a variable concisely and clearly.
|
||||
It is designed to be clear precise and short, much like the help of some
|
||||
command-line utility when you type the command with the `--help` or `-h` option.
|
||||
|
||||
A :term:`help` helps to clarify any ambiguity about the variable’s purpose. It can be long and detailed.
|
||||
|
||||
We can set :term:`help` attribute to a variable or to a family.
|
||||
|
||||
.. keypoints:: Key points
|
||||
|
||||
- We have seen how to give examples, simply with the `examples` parameter
|
||||
- We have seen how to specify a help, simply with the `help` parameter
|
||||
|
||||
398
docs/tutorial/dynamic.rst
Normal file
|
|
@ -0,0 +1,398 @@
|
|||
.. _tutorial_dynamic:
|
||||
|
||||
A dynamically built family
|
||||
==========================
|
||||
|
||||
.. objectives:: Objectives
|
||||
|
||||
In this section we will learn how to create a dynamically built family.
|
||||
|
||||
In a dynamically built family, instead of duplicating the definition of
|
||||
identical variables in several families, they can be generated automatically.
|
||||
|
||||
.. prerequisites:: Prerequisites
|
||||
|
||||
- We assume that Rougail's library is :ref:`installed <installation>` on your computer.
|
||||
|
||||
- It is possible to retrieve the current state of the various Rougail files manipulated in this tutorial step
|
||||
by checking out the corresponding tag of the `rougail-tutorials` git repository.
|
||||
Each tag corresponds to a stage of progress in the tutorial.
|
||||
Of course, you can also decide to copy/paste or download the tutorial files contents while following the tutorial steps.
|
||||
|
||||
If you want to follow this tutorial with the help of the corresponding :tutorial:`rougail-tutorials git repository <src/branch/1.1>`,
|
||||
this workshop page corresponds to the tags :tutorial:`v1.1_060 <src/tag/v1.1_060/README.md>` to :tutorial:`v1.1_061 <src/tag/v1.1_061/README.md>`
|
||||
in the repository.
|
||||
|
||||
::
|
||||
|
||||
git clone https://forge.cloud.silique.fr/stove/rougail-tutorials.git
|
||||
git switch --detach v1.1_060
|
||||
|
||||
We handled the HTTPS mode in the previous section. But there's more modes to handle.
|
||||
Let's turn back to the firefox's configuration page:
|
||||
|
||||
.. image:: images/soksv5.png
|
||||
|
||||
We see that we need to handle the SOCKS configuration in addition to the HTTPS configuration.
|
||||
Moreover, we can see that these two groups of variables (also known as family) are similar in the structure:
|
||||
they both have a host and a port.
|
||||
|
||||
There are two proxies that are to be configured :
|
||||
|
||||
- the HTTPS proxy
|
||||
- the SOCKS proxy
|
||||
|
||||
As they have the same structure, would it be possible to define the two of them
|
||||
in one shot?
|
||||
|
||||
.. note:: It's not the place here to describe what the HTTP and SOCKS protocols are.
|
||||
The interesting point here is that they are very similar in our firefox's
|
||||
configuration and that we can do batch processing.
|
||||
|
||||
.. index:: dynamically built family
|
||||
|
||||
Family: A dynamically built family
|
||||
-------------------------------------
|
||||
|
||||
With Rougail, it is possible to create some kind of a model of family.
|
||||
Kind of a generic family declaration.
|
||||
We call this generic family creation process a dynamic creation because as we will see below,
|
||||
these families exist at the very moment we define their **identifiers**.
|
||||
|
||||
First, here is what we need to make (without identifiers):
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
https_proxy:
|
||||
description: HTTPS Proxy
|
||||
...
|
||||
|
||||
address:
|
||||
description: HTTPS address
|
||||
...
|
||||
|
||||
port:
|
||||
description: HTTPS Port
|
||||
...
|
||||
|
||||
sock_proxy:
|
||||
description: SOCKS Proxy
|
||||
...
|
||||
|
||||
address:
|
||||
description: SOCKS address
|
||||
...
|
||||
|
||||
port:
|
||||
description: SOCKS Port
|
||||
...
|
||||
|
||||
Now with identifiers, we have the ability to declare our families this way:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
"{{ identifier }}_proxy":
|
||||
description: "{{ identifier }} Proxy"
|
||||
dynamic:
|
||||
- HTTPS
|
||||
- SOCKS
|
||||
...
|
||||
|
||||
address:
|
||||
description: "{{ identifier }} address"
|
||||
...
|
||||
|
||||
port:
|
||||
description: "{{ identifier }} port"
|
||||
...
|
||||
|
||||
.. type-along:: What is exactly an identifier?
|
||||
|
||||
If you used the YAML declaration tool named `Ansible <https://docs.ansible.com>`_,
|
||||
the variable used to iterate over multiple values in a task is called an **`item`**.
|
||||
We call it an identifier.
|
||||
|
||||
It is a symbol used in the context of a loop. For example:
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: A code example of an ansible loop
|
||||
|
||||
- name: Loop example with 'item'
|
||||
ansible.builtin.debug:
|
||||
msg: "The current value is {{ item }}"
|
||||
loop:
|
||||
- value1
|
||||
- value2
|
||||
- value3
|
||||
|
||||
This code will output:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
The current value is value1
|
||||
The current value is value2
|
||||
The current value is value3
|
||||
|
||||
In the Rougail context, we name this item an identifier because it is an item
|
||||
that allow us to define dynamically family names.
|
||||
|
||||
.. glossary::
|
||||
|
||||
identifier
|
||||
|
||||
In the :ref:`dynamically built family creation field <tutorial_dynamic>` we call an identifier
|
||||
an item that defines a family name. An item is a variable on which an iteration
|
||||
on keywords will be carried out.
|
||||
|
||||
An :term:`identifier` is a local variable, used only for creating multiple
|
||||
iterations, used for creating multiple families in only one declaration.
|
||||
|
||||
It allows us to declare very similar families in a more generic way.
|
||||
|
||||
Here is the syntax we are using that allows the declaration of multiple families at one time:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
"{{ identifier }}_proxy":
|
||||
description: "{{ identifier }} Proxy"
|
||||
dynamic:
|
||||
- HTTPS
|
||||
- SOCKS
|
||||
|
||||
This identifier is a parameter that enables us to create two families named `https_proxy` and `socks_proxy`:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
https_proxy:
|
||||
description: "HTTPS Proxy"
|
||||
|
||||
socks_proxy:
|
||||
description: "SOCKS Proxy"
|
||||
|
||||
.. attention:: Be careful when choosing your identifiers items: pay attention that the family
|
||||
names that will be dynamically created have not been declared before in some other
|
||||
YAML structure file.
|
||||
|
||||
Here the family name is: `"{{ identifier }}_proxy"`.
|
||||
|
||||
If you define a dynamically built family with the `https` identifer that will
|
||||
build a `https_proxy` family and if this familiy already exists,
|
||||
then rougail will raise a family/variable override warning.
|
||||
|
||||
When choosing a dynamically built family name, rougail will replace spaces, accents, uppercases...
|
||||
by valid character and put all in lowercase. Have a look at the :ref:`naming convention <namingconvention>`.
|
||||
|
||||
As you can see here, the identifier is `HTTPS`, but the name clearly contains `https` (in lowercase).
|
||||
|
||||
Here is our dynamically built familiy in situation in the :file:`firefox/20-manual.yml` structure file.
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_060/firefox/20-manual.yml
|
||||
:language: yaml
|
||||
:caption: The :file:`firefox/20-manual.yml` structure file with the dynamically built families
|
||||
|
||||
..
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
manual:
|
||||
|
||||
use_for_https: true # Also use this proxy for HTTPS
|
||||
|
||||
'{{ identifier }}_proxy':
|
||||
description: '{{ identifier }} Proxy'
|
||||
hidden:
|
||||
variable: _.use_for_https
|
||||
dynamic:
|
||||
- HTTPS
|
||||
- SOCKS
|
||||
|
||||
address:
|
||||
description: '{{ identifier }} address'
|
||||
default:
|
||||
variable: __.http_proxy.address
|
||||
|
||||
port:
|
||||
description: '{{ identifier }} port'
|
||||
default:
|
||||
variable: __.http_proxy.port
|
||||
...
|
||||
|
||||
Here is the user data file on which we will launch the Rougail CLI:
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_060/config/01/config.yml
|
||||
:language: yaml
|
||||
:caption: The :file:`config/01/config.yml` user data file
|
||||
|
||||
..
|
||||
---
|
||||
proxy_mode: Manual proxy configuration
|
||||
manual:
|
||||
http_proxy:
|
||||
address: http.proxy.net
|
||||
port: 3128
|
||||
use_for_https: false
|
||||
https_proxy:
|
||||
address: https.proxy.net
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_060/config/01/cmd_ro.txt
|
||||
:class: terminal
|
||||
|
||||
..
|
||||
rougail -m firefox/ -u yaml -yf config/01/config.yml
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_060/config/01/output_ro.html
|
||||
:class: output
|
||||
|
||||
..
|
||||
rougail -m firefox/proxy.yml -u yaml --yaml.filename config/proxy.yml
|
||||
╭─────────────────── Caption ────────────────────╮
|
||||
│ Variable Default value │
|
||||
│ Unmodifiable variable Modified value │
|
||||
│ (Original default value) │
|
||||
╰────────────────────────────────────────────────╯
|
||||
Variables:
|
||||
┗━━ 📂 Manual proxy configuration
|
||||
┣━━ 📂 HTTP Proxy
|
||||
┃ ┣━━ 📓 HTTP address: ... (loaded from the YAML file "userdata/proxy.yml")
|
||||
┃ ┗━━ 📓 HTTP Port: ... (8080 - loaded from the YAML file "userdata/proxy.yml")
|
||||
┣━━ 📓 Also use this proxy for HTTPS: true
|
||||
┣━━ 📂 HTTPS Proxy
|
||||
┃ ┣━━ 📓 HTTPS address: ...
|
||||
┃ ┗━━ 📓 HTTPS port: ...
|
||||
┗━━ 📂 SOCKS Proxy
|
||||
┣━━ 📓 SOCKS address: ...
|
||||
┗━━ 📓 SOCKS port: ...
|
||||
|
||||
We can see that the dynamically built families that have been created:
|
||||
|
||||
- an `HTTPS Proxy` family
|
||||
- a `SOCKS Proxy` family
|
||||
|
||||
and, as we expected, containing an address and a port.
|
||||
|
||||
A conditional disabled variable with dynamic identifier
|
||||
--------------------------------------------------------
|
||||
|
||||
.. type-along:: For those who follow the tutorial with the help of the git repository
|
||||
|
||||
Now you need to checkout the :tutorial:`v1.1_061 <src/tag/v1.1_061/README.md>` version::
|
||||
|
||||
git switch --detach v1.1_061
|
||||
|
||||
Here is the final version of the HTTPS and SOCKS structure file, we have added
|
||||
a new variable named `version`, with the `choice` type, with a default value,
|
||||
and which has the `disabled` property if the :term:`configuration` is in the `SOCKS` situation.
|
||||
We will look at this in more detail below.
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_061/firefox/20-manual.yml
|
||||
:language: yaml
|
||||
:caption: The final :file:`firefox/20-proxy.yml` structure file
|
||||
|
||||
..
|
||||
%YAML 1.2
|
||||
---
|
||||
version: 1.1
|
||||
|
||||
manual:
|
||||
|
||||
use_for_https: true # Also use this proxy for HTTPS
|
||||
|
||||
'{{ identifier }}_proxy':
|
||||
description: '{{ identifier }} Proxy'
|
||||
hidden:
|
||||
variable: _.use_for_https
|
||||
dynamic:
|
||||
- HTTPS
|
||||
- SOCKS
|
||||
|
||||
address:
|
||||
description: '{{ identifier }} address'
|
||||
default:
|
||||
variable: __.http_proxy.address
|
||||
|
||||
port:
|
||||
description: '{{ identifier }} port'
|
||||
default:
|
||||
variable: __.http_proxy.port
|
||||
|
||||
version:
|
||||
description: SOCKS host version used by proxy
|
||||
choices:
|
||||
- v4
|
||||
- v5
|
||||
default: v5
|
||||
disabled:
|
||||
type: identifier
|
||||
when: HTTPS
|
||||
...
|
||||
|
||||
The disabled `property` is assigned here to the `version` variable
|
||||
in the case where the identifier is `HTTPS`.
|
||||
|
||||
This means that when the current dynamically built family is determined by the identifier `HTTPS`, the variable `version` is disabled
|
||||
(therefore considered as non-existent) and when the identifier is `SOCKS` the variable is present (it is accessible).
|
||||
|
||||
..
|
||||
version:
|
||||
description: SOCKS host version used by proxy
|
||||
choices:
|
||||
- v4
|
||||
- v5
|
||||
default: v5
|
||||
disabled:
|
||||
type: identifier
|
||||
when: HTTPS
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_061/config/01/config.yml
|
||||
:language: yaml
|
||||
:caption: The :file:`config/01/config.yml` user data file
|
||||
|
||||
..
|
||||
---
|
||||
proxy_mode: Manual proxy configuration
|
||||
manual:
|
||||
http_proxy:
|
||||
address: http.proxy.net
|
||||
port: 3128
|
||||
use_for_https: false
|
||||
https_proxy:
|
||||
address: https.proxy.net
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_061/config/01/cmd_ro.txt
|
||||
:class: terminal
|
||||
|
||||
..
|
||||
rougail -m firefox/ -u yaml -yf config/01/config.yml
|
||||
|
||||
The Rougail CLI outputs this:
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_061/config/01/output_ro.html
|
||||
:class: output
|
||||
|
||||
..
|
||||
Variables:
|
||||
┣━━ 📓 Configure Proxy Access to the Internet: Manual proxy configuration ◀ loaded from the YAML file "config/01/config.yml" (⏳ No proxy)
|
||||
┗━━ 📂 Manual proxy configuration
|
||||
┣━━ 📂 HTTP Proxy
|
||||
┃ ┣━━ 📓 HTTP address: http.proxy.net ◀ loaded from the YAML file "config/01/config.yml"
|
||||
┃ ┗━━ 📓 HTTP Port: 3128 ◀ loaded from the YAML file "config/01/config.yml" (⏳ 8080)
|
||||
┣━━ 📓 Also use this proxy for HTTPS: false ◀ loaded from the YAML file "config/01/config.yml" (⏳ true)
|
||||
┣━━ 📂 HTTPS Proxy
|
||||
┃ ┣━━ 📓 HTTPS address: https.proxy.net ◀ loaded from the YAML file "config/01/config.yml" (⏳ http.proxy.net)
|
||||
┃ ┗━━ 📓 HTTPS port: 3128
|
||||
┗━━ 📂 SOCKS Proxy
|
||||
┣━━ 📓 SOCKS address: http.proxy.net
|
||||
┣━━ 📓 SOCKS port: 3128
|
||||
┗━━ 📓 SOCKS host version used by proxy: v5
|
||||
|
||||
.. keypoints:: Key points
|
||||
|
||||
- We now know how to declare a dynamically built family, with setting its identifier.
|
||||
- we have a new use case for the `disabled` property.
|
||||
We know how to disable a dynamically built variable based on a familiy identifier.
|
||||
|
||||
276
docs/tutorial/family.rst
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
Group variables inside families
|
||||
=================================
|
||||
|
||||
.. objectives:: Objectives
|
||||
|
||||
We will learn how to:
|
||||
|
||||
- create a :term:`family`
|
||||
- gather :term:`variable`\ s into a :term:`family`
|
||||
- make a variable within a variable, which turns this variable container into being a family
|
||||
|
||||
.. prerequisites:: Prerequisites
|
||||
|
||||
- We assume that Rougail's library is :ref:`installed <installation>` on your computer.
|
||||
|
||||
- It is possible to retrieve the current state of the various Rougail files manipulated in this tutorial step
|
||||
by checking out the corresponding tag of the `rougail-tutorials` git repository.
|
||||
Each tag corresponds to a stage of progress in the tutorial.
|
||||
Of course, you can also decide to copy/paste or download the tutorial files contents while following the tutorial steps.
|
||||
|
||||
If you want to follow this tutorial with the help of the corresponding :tutorial:`rougail-tutorials git repository <src/branch/1.1>`,
|
||||
this workshop page corresponds to the tags :tutorial:`v1.1_020 <src/tag/v1.1_020/README.md>` to :tutorial:`v1.1_022 <src/tag/v1.1_022/README.md>`
|
||||
in the repository.
|
||||
|
||||
::
|
||||
|
||||
git clone https://forge.cloud.silique.fr/stove/rougail-tutorials.git
|
||||
git switch --detach v1.1_020
|
||||
|
||||
.. type-along:: Let's recap how far we've come
|
||||
|
||||
We have this choice variable in its structure definition file:
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_010/firefox/00-proxy.yml
|
||||
:linenos:
|
||||
:language: yaml
|
||||
:caption: The `proxy_mode` choice variable in the :file:`firefox/00-proxy.yml` structure file
|
||||
|
||||
..
|
||||
---
|
||||
proxy_mode:
|
||||
description: Configure Proxy Access to the Internet
|
||||
choices:
|
||||
- No proxy
|
||||
- Auto-detect proxy settings for this network
|
||||
- Use system proxy settings
|
||||
- Manual proxy configuration
|
||||
- Automatic proxy configuration URL
|
||||
default: No proxy
|
||||
|
||||
.. We're gonna put it in a :term:`family`.
|
||||
|
||||
In short, let's describe our `proxy_mode` variable like this:
|
||||
|
||||
.. confval:: proxy_mode
|
||||
:type: `choice`
|
||||
:default: No proxy
|
||||
|
||||
Proxy mode's settings
|
||||
|
||||
Now we will define new variables, and other structure definitions.
|
||||
For the sake of clarity, we will put the structure definitions in separate files.
|
||||
Please have a look at the :ref:`file naming and organizing convention <namingconvention>`.
|
||||
|
||||
Here we made a :file:`firefox/00-proxy.yml` structure file and we're gonna make
|
||||
a new structure file named :file:`firefox/10-manual.yml`::
|
||||
|
||||
.
|
||||
└── firefox
|
||||
├── 00-proxy.yml
|
||||
└── 10-manual.yml
|
||||
|
||||
Creating a new family
|
||||
-----------------------
|
||||
|
||||
Let's create a family named `manual` which obviously corresponds to the proxy's manual configuration choice.
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_020/firefox/10-manual.yml
|
||||
:language: yaml
|
||||
:caption: A family structure file description named `manual` in a :file:`firefox/10-manual.yml` file
|
||||
:name: RougailManualFamily
|
||||
|
||||
..
|
||||
---
|
||||
manual:
|
||||
description: Manual proxy configuration
|
||||
type: family
|
||||
|
||||
We can see that we have defined a :term:`family` here, and this family is *empty*
|
||||
which means that this family is a container variable that contains no variable yet.
|
||||
|
||||
.. warning::
|
||||
|
||||
If a family is empty, we need to specify the :term:`family` type here because if we don't,
|
||||
the Rougail's type engine will infer it by default as a :term:`variable`.
|
||||
We have to force the family type inference.
|
||||
|
||||
It's because we don't have set any :term:`variable` inside yet. When we will have a variable inside of this family,
|
||||
we will make a YAML block (to create a block in YAML, you just need to indent the lines) and the Rougail's type inference engine will implicitely infer the variable's container as a family type.
|
||||
|
||||
.. important::
|
||||
|
||||
Any family that has been declared in a structure file but is empty (i.e., contains neither :term:`variables <variable>` nor :term:`subfamilies <subfamily>`) is not taken into account by the low level :term:`Tiramisu <tiramisu>` consistency engine.
|
||||
|
||||
Or a sub family
|
||||
----------------
|
||||
|
||||
.. type-along:: For those who follow the tutorial with the help of the git repository
|
||||
|
||||
Now you need to checkout the :tutorial:`v1.1_021 <src/tag/v1.1_021/README.md>` version::
|
||||
|
||||
git switch --detach v1.1_021
|
||||
|
||||
.. glossary::
|
||||
|
||||
sub family
|
||||
|
||||
A sub family is a family inside a family.
|
||||
|
||||
Creating a family hierarchy of families (family inside a family) is very easy:
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_021/firefox/10-manual.yml
|
||||
:language: yaml
|
||||
:caption: A rougail structure description file with a hierarchy.
|
||||
:name: RougailFirstFamilyHierarchy
|
||||
|
||||
..
|
||||
---
|
||||
manual:
|
||||
description: Manual proxy configuration
|
||||
type: family
|
||||
|
||||
http_proxy:
|
||||
description: HTTP Proxy
|
||||
type: family
|
||||
|
||||
:tutorial:`Download this file from the rougail-tutorials git repository <src/tag/v1.1_021/firefox/00-proxy.yml>`
|
||||
|
||||
Here in our use case we used the :term:`short-hand declaration mode <short-hand notation>`
|
||||
to declare our `manual` family:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
manual: # Manual proxy configuration
|
||||
|
||||
And the `http_proxy` family lives inside of this `manual` family.
|
||||
We therefore created a hierarchy of families.
|
||||
|
||||
Putting a variable inside of a family or a sub family
|
||||
-----------------------------------------------------------
|
||||
|
||||
.. type-along:: For those who follow the tutorial with the help of the git repository
|
||||
|
||||
Now you need to checkout the :tutorial:`v1.1_022 <src/tag/v1.1_022/README.md>` version::
|
||||
|
||||
git switch --detach v1.1_022
|
||||
|
||||
We are going to put a variable inside of a family or a sub family
|
||||
|
||||
Let's create a variable in the `http_proxy` family.
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_022/firefox/10-manual.yml
|
||||
:language: yaml
|
||||
:caption: An `address` variable in the `http_proxy` family
|
||||
:name: RougailVariableInSubFamily
|
||||
|
||||
..
|
||||
---
|
||||
manual:
|
||||
description: Manual proxy configuration
|
||||
type: family
|
||||
|
||||
http_proxy:
|
||||
description: HTTP Proxy
|
||||
type: family
|
||||
|
||||
address:
|
||||
description: HTTP address
|
||||
|
||||
:tutorial:`Download this file from the rougail-tutorials git repository <src/tag/v1.1_022/firefox/10-manual.yml>`
|
||||
|
||||
Now that the :confval:`address` variable is declared, the :term:`operator` can set :term:`a value <value>` to it.
|
||||
|
||||
In short, let's describe our `address` variable like this:
|
||||
|
||||
.. confval:: address
|
||||
:default: None
|
||||
|
||||
This is the HTTP address of the proxy
|
||||
|
||||
We have reached the definition of the address in the `http_proxy` family; there will be other variables to define in this family.
|
||||
|
||||
.. image:: images/firefox_manual_family.png
|
||||
|
||||
.. type-along:: Assigning a user value
|
||||
|
||||
Now we need to set a value for the :confval:`address` variable,
|
||||
otherwise we will get an error if we try to access this variable:
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_022/config/01/output_ro.html
|
||||
:class: error-box
|
||||
|
||||
..
|
||||
<pre>🛑 ERRORS
|
||||
<span style="color: #ff0000">┣━━ </span>The following variables are mandatory but have no value:
|
||||
<span style="color: #ff0000">┗━━ </span> - manual.http_proxy.address (HTTP address)
|
||||
</pre>
|
||||
|
||||
.. type-along:: Let's set user values in a user data file
|
||||
|
||||
Here is a user data file sample:
|
||||
|
||||
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_022/config/02/config.yml
|
||||
:language: yaml
|
||||
:caption: A user file named :file:`config/03/config.yml` with a value set for the `address` variable
|
||||
:name: RougailAddresseVariableUserValue
|
||||
|
||||
..
|
||||
---
|
||||
proxy_mode: Manual proxy configuration
|
||||
manual:
|
||||
http_proxy:
|
||||
address: example.net
|
||||
|
||||
:tutorial:`Download this file from the rougail-tutorials git repository <src/tag/v1.1_022/config/02/config.yml>`
|
||||
|
||||
Let's validate the consitency of the :term:`configuration`:
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_022/config/02/cmd_ro.txt
|
||||
:class: terminal
|
||||
|
||||
..
|
||||
rougail -m firefox/ -u yaml -yf config/02/config.yml
|
||||
|
||||
Everything is OK:
|
||||
|
||||
.. raw:: html
|
||||
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_022/config/02/output_ro.html
|
||||
:class: output
|
||||
|
||||
..
|
||||
<pre>╭──────── Caption ────────╮
|
||||
│ Variable <span style="color: #ffd700">Default value</span> │
|
||||
│ Modified value │
|
||||
╰─────────────────────────╯
|
||||
Variables:
|
||||
<span style="color: #5c5cff">┣━━ </span>📓 Configure Proxy Access to the Internet: <span style="color: #ffd700">No proxy</span>
|
||||
<span style="color: #5c5cff">┗━━ </span>📂 Manual proxy configuration
|
||||
<span style="color: #5c5cff"> </span><span style="color: #5c5cff">┗━━ </span>📂 HTTP Proxy
|
||||
<span style="color: #5c5cff"> </span><span style="color: #5c5cff"> </span><span style="color: #5c5cff">┗━━ </span>📓 HTTP address: example.net ◀ loaded from the YAML file "config/02/config.yml"
|
||||
</pre>
|
||||
|
||||
Let's recap about the user data. We can see in this Rougail CLI output that:
|
||||
|
||||
- the `proxy_mode` value is set by default by the :term:`integrator`
|
||||
- the `address` value is has been set by an :term:`operator`
|
||||
|
||||
.. keypoints:: Let's review the key points
|
||||
|
||||
**Keywords**
|
||||
|
||||
- we know how to define :term:`variable`\ s inside of a family
|
||||
- we now know what a :term:`mandatory` variable is and why it is necessary to assign values to the variables
|
||||
- we kwow how to set a variable's :term:`user value <user data>`
|
||||
- we have the big picture : the :term:`configuration`, which is (the structure files + the user data files)
|
||||
|
||||
**Progress**
|
||||
|
||||
- we have a :term:`family` named `manual` and a sub family named `http_proxy`
|
||||
- And we have now two variables: :confval:`proxy_mode` and :confval:`address`.
|
||||
|
||||
.. seealso::
|
||||
|
||||
The full documentation about a :term:`family`.
|
||||
BIN
docs/tutorial/images/QuestionaryChoice.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
docs/tutorial/images/UserDataOutput.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 123 KiB After Width: | Height: | Size: 123 KiB |
BIN
docs/tutorial/images/firefox130.png
Normal file
|
After Width: | Height: | Size: 118 KiB |
BIN
docs/tutorial/images/firefox160.png
Normal file
|
After Width: | Height: | Size: 118 KiB |
BIN
docs/tutorial/images/firefox_01.png
Normal file
|
After Width: | Height: | Size: 119 KiB |
BIN
docs/tutorial/images/firefox_02.png
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
docs/tutorial/images/firefox_manual_family.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
docs/tutorial/images/firefox_manual_https.png
Normal file
|
After Width: | Height: | Size: 118 KiB |
BIN
docs/tutorial/images/firefox_port.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
docs/tutorial/images/firefox_soks_version.png
Normal file
|
After Width: | Height: | Size: 118 KiB |
BIN
docs/tutorial/images/foxyproxy.png
Normal file
|
After Width: | Height: | Size: 154 KiB |
BIN
docs/tutorial/images/integrator.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
docs/tutorial/images/operator.png
Normal file
|
After Width: | Height: | Size: 7 KiB |