This application allows to replicate a file structure using a reference file structure (so-called skeleton) and a list of predefined variables.
The classic usecase is to build a dozen of Dockerfiles for the different versions of environment.
File structure:
┌skeletons/php/Dockerfile.template
├main.py
└config.yaml
config.yaml:
skeletons:
- php
var:
COMMON_HEADER: "# This is an autogenerated file"
out:
- php-8.0:
skeleton: php
var:
VERSION: 8.0
WITH_XDEBUG: ""
- php-8.0-with-xdebug:
skeleton: php
var:
VERSION: 8.0
WITH_XDEBUG: "1"
XDEBUG_VERSION: "3.1.4"
- php-8.1:
skeleton: php
var:
VERSION: 8.1
WITH_XDEBUG: ""
- php-8.1-with-xdebug:
skeleton: php
var:
VERSION: 8.1
WITH_XDEBUG: "1"
XDEBUG_VERSION: "3.1.5"
skeletons/my-skeleton/Dockerfile.template:
{{COMMON_HEADER}}
ARG PHP_VERSION={{VERSION}}
FROM php:${VERSION}-fpm-alpine
{% if WITH_XDEBUG -%}
RUN pecl install xdebug-{{XDEBUG_VERSION}} && docker-php-ext-enable xdebug
{% endif -%}
# The rest of the file is cut for the sake of brevity
Now you are ready to run python3 main.py update to get 4 different Dockerfiles:
out
├ php-8.0/Dockerfile
├ php-8.0-with-xdebug/Dockerfile
├ php-8.1/Dockerfile
└ php-8.1-with-xdebug/Dockerfile
Need more variations? Just replicate the entries in the out section of the config.yaml and change the variable values accordingly!
A reference file structure(s) is/are located in the skeletons directory.
All generated sets of files are put into the out directory.
The application takes a config file in the YAML format.
To start generation one need to use update command:
python3 main.py update
It takes no arguments as by default it uses config.yaml from the current directory as a config file.
But the update command still has some aux options that are listed below:
| Short | Long | Parameter | Description |
|---|---|---|---|
| -c | --config | PATH | Config yaml file path |
| -d | --directory | PATH | Working directory path |
| --dry-run | Just check the validity of the config |
Config file has 3 basic sections:
- skeletons - all available skeletons are listed here.
- var - global (common) variables are listed here
- out - all target structures are listed here
All names are using 1 to 1 mapping to the filesystem which means that
skeletons:
- node
is searched in ./skeletons/node directory while the generated item
out:
- node-16
will be placed into the ./out/node-16 directory
There is no much to say. Basically this is a list:
skeletons:
- skeleton_1
- skeleton_2
- skeleton_3
All the declared in the config file skeletons should be existing subdirectories of the skeletons directory. The application validates that.
Just another list of variables that is common for all parsed templates:
var:
# This variable could be used as a common header that is available in any template
HEADER: |
#
# 'Twas brillig, and the slithy toves
# Did gyre and gimble in the wabe;
# All mimsy were the borogoves,
# And the mome raths outgrabe.
#
Don't be scared or confused with pipes and hashes - this is how multiline value is written in YAML. Check out YAML reference or config.yaml.sample for more details.
Pretty easy:
out:
- generated_item_1:
skeleton: skeleton_1
var:
some_var_1: value
some_var_2: another_value
- generated_item_2:
skeleton: skeleton_1
var:
some_var_1: some_value
some_var_2: yet_another_value
Basically all items in the out section should have a title and a reference to the skeleton that is declared in the skeletons section.
All files of the skeleton with .template extension are considered to be Jinja2 templates. Such files are parsed with Jinja2 engine and have .template extension stripped afterwards.
Yes, that's what variables are intended for, but Jinja2 significantly more powerful, just check it out.
- Inactive config file items. It is possible to have inactive items this way:
out:
- generated_item_1:
skeleton: skeleton_1
var:
some_var_1: value
some_var_2: another_value
inactive:
- generated_item_2: # this one will be ignored
skeleton: skeleton_1
var:
some_var_1: some_value
some_var_2: yet_another_value
Above we created a non-standard config section with the name inactive which will be ignored by the script.
-
Please note that out directory content is completely regenerated every time you run
updatecommand. In case you need to save the generated directory after the respective section was removed from the config file you need to copy it somewhere before runningupdatecommand -
In addition to the
updatecommand there is aprintcommand that is used to list the current out directory content. In case out directory is empty or missing the output of the print command will be the following:
> python3 main.py
No tags available
>
print command has the following aux options:
| Short | Long | Parameter | Description |
|---|---|---|---|
| -d | --directory | PATH | Working directory path |
This work is provided under the MIT License. See the included LICENSE file.