Jinja2++ is a drop in single file solution for templating with Variable Precedence.

You can use ANY language!

How it works

Based on the Unix pipeline : JSON - stdin |> stdout - JSON

A var_file is any executable that slurps JSON from STDIN, and spits JSON from STD out.

We assemble a series of cascading var_files based on the file hierarchy to overwrite proceeding variables.

We also do context injection, in the same fashion, ie context as the local path of each var_file / template, etc


Variable precedence

|── vars.perl* <- [[base variables]]
├── filters.py* <- inject ((J2 filters)) with ~vanilla python~ functions!
├── render_inject.rb* <- inject && overwrite [pre-render context] variables
├── var_inject.sh* <- inject && overwrite [pre-script context] variables
├── monitoring/
│  ├── grafana/
│  │  ├── templates/
│  │  ├── Chart.yaml.j2
│  │  └── vars.js* <- [overwrite] variables here
│  ├── iperf/
│  │  ├── templates/
│  │  ├── Chart.yaml.j2
│  │  └── vars.fsi* <- [overwrite] variables here
│  ├── prometheus/
│  │  ├── templates/
│  │  ├── Chart.yaml.j2
│  │  └── vars.exe* <- [overwrite] variables here

Dry runs



Syntax highlighted diff



Dynamic J2 filter import

Write your filters as vanilla Python functions.

like so:

def drop_first(lst):
  return lst[1:]

def base64(x, indent=0):
  encoded = str(b64.b64encode(x.strip().encode("utf-8")), "utf-8")
  return (" " * indent) + (encoded if encoded else "")

Context injection

The following [context variables] will be injected before each var_file / template.

add more of your own!

{"src": "...",
 "_dest_": "...",
 "_dir_": "...",
 "_parent_": "...",
 "_grand_parent_": "...",
 "_var_file_/_template_": "..."}


Simply call ./j2pp.py with the following:

Note: For large projects you may need to call ulimit -S -n <number> to increase # of concurrent open files by a unix process.

This is required prior to calling ./j2pp.py due to the fact that it does parallel processing.



Put all your .j2 templates here, along with var_files.


Your finished templates go here.


Any file paths in exclude will be skipped. i.e. --exclude .s .skip


A VAR_FILE is an executable: .py, .sh, et al.
VAR_FILES are how you do variable injections.
JSON - stdin |> stdout - JSON.
VAR_FILES are placed in the file hierarchy
beween *.j2 and SRC.
VAR_FILES closes to *.j2 have higher precedence.


All functions in IMPORT_FILTERS will be included as
j2 filters. Must be python files.


Same semantics as VAR_FILES,
except run before each VAR_FILE.


Same semantics as VAR_FILES,
except run before each .j2 file is rendered.


Inject variables with JSON.
Highest precedence, also available to all var files.


Default is 🦄.
Any stdout in VAR_FILES before the last occurance
of 🦄 will be treated as comments.
🦄 is entirely optional.


Just do a diff, dont write to file.


Dont print diff.


Used to print diff, if your terminal is kinda wonky,
pick one with less colours.