Hey @audreyr @pydanny @hackebrot, happy new year and thank you all for maintaining this project. Is awesome.
This project helps me to deliver better and faster but lacks an important feature (IMHO).
Template inheritance
This issue (and the attached pr) aims to implement a templates directory so a maintainer can use extends, includes, blocks, import and super inside the cookiecutter project template.
Motivation
Exists a lot of cases where an option can drastically change a whole file, or you need to include some repeatable fields.
For example, we have a cookiecutter were an option changes completely the ci file. This is a simple problem but requires some effort (check Alternative Considered) when a template engine is built to solve this kind of problem.
Cookiecutter use jinja under the hood to render the project boilerplate but at render time doesn't have any knowledge about the original project template (as also stated here for example), this means that all files should be included inside the cookiecutter template before the render happen.
But with this behaviour, the user is forced to bypass these mechanics when the project becomes complex.
User Benefit
User can finally use jinja Template Inheritance, and this includes (tl;dr):
- extends
- blocks
- super
- scoped
- import
- include
This works really well with directories options.
This can step into #59 because if templates are pluggable from the outside, we can include external package templates into the loader as well (in a second iteration).
This may also fit in #1004 if we use the base template as a master template.
There are other requests for this like #818, #409 and other similar grouped by #364 or like #1479
I know that cookiecutter is a very conservative project, but this is a little change with no impact has a high ROI.
Design Proposal
to implement this we just need to add ../templates in the cookiecutter env.loader
in this way and generating a cookiecutter like this:
https://github.com/user/repo-name.git
├── {{cookiecutter.project_slug}}/
| └── file.txt
├── templates/
| └── base.txt
└── cookiecutter.json
we can load into the jinja env every file listed under that directory and use it in cookiecutter templates like this:
or
And so on.
Alternatives Considered
Now, this can be implemented in a few ways:
- giant if statements
{# config.txt #}
{% if True%}
{# whole config A (200 lines of codes)#}
{% else %}
{# whole config B (250 lines of codes)#}
{% endif%}
and the readability is a mess
- pre/post hooks
we can add a cleaning/renaming/moving function before or after the baking process but is very complicated and require "magic":
if "{{ cookiecutter.is_A }}".lower() == "y":
os.remove("configB")
os.rename('configA','config')
if "{{ cookiecutter.is_B}}".lower() == "y":
os.remove("configA")
os.rename('configB','config')
as a reference: https://github.com/pydanny/cookiecutter-django/blob/master/hooks/post_gen_project.py
- using logic in the filename
https://github.com/user/repo-name.git
├── `{% if cookiecutter.is_B %}config{% endif %}`
└── `{% if cookiecutter.is_A %}config{% endif %}`
this logic can be really helpful when you need not render specific files or directory
but not when you need to extend common configurations.
- template inside the project and hook to remove it after
https://github.com/user/repo-name.git
├── {{cookiecutter.project_slug}}/
| ├── templates/
| | └── base.txt
| └── file.txt
└── cookiecutter.json
and somewhere at post gen hooks
...
shutil.rmtree("templates")
...
Compatibility
This implementation is full retro compatible with already baked cookiecutter.
there are two main scenarios:
- the project doesn't have a
templates dir: the templates directory is optional, so no harm here.
- the project already have a
templates dir: all keyword implemented have no sense before this implementation so that no one can use it, this means that the templates will be loaded, but we can exclude the use.
Questions and Discussion Topics
- There are other cases not included?
- What do you think about it?
templates is a too generic name?
Let me know!
Hey @audreyr @pydanny @hackebrot, happy new year and thank you all for maintaining this project. Is awesome.
This project helps me to deliver better and faster but lacks an important feature (IMHO).
Template inheritance
This issue (and the attached pr) aims to implement a
templatesdirectory so a maintainer can useextends,includes,blocks,importandsuperinside thecookiecutterproject template.Motivation
Exists a lot of cases where an option can drastically change a whole file, or you need to include some repeatable fields.
For example, we have a cookiecutter were an option changes completely the ci file. This is a simple problem but requires some effort (check Alternative Considered) when a template engine is built to solve this kind of problem.
Cookiecutter use jinja under the hood to render the project boilerplate but at render time doesn't have any knowledge about the original project template (as also stated here for example), this means that all files should be included inside the cookiecutter template before the render happen.
But with this behaviour, the user is forced to bypass these mechanics when the project becomes complex.
User Benefit
User can finally use jinja Template Inheritance, and this includes (tl;dr):
This works really well with directories options.
This can step into #59 because if templates are pluggable from the outside, we can include external package templates into the loader as well (in a second iteration).
This may also fit in #1004 if we use the base template as a master template.
There are other requests for this like #818, #409 and other similar grouped by #364 or like #1479
I know that cookiecutter is a very conservative project, but this is a little change with no impact has a high ROI.
Design Proposal
to implement this we just need to add
../templatesin the cookiecutter env.loaderin this way and generating a cookiecutter like this:
we can load into the jinja env every file listed under that directory and use it in cookiecutter templates like this:
or
And so on.
Alternatives Considered
Now, this can be implemented in a few ways:
and the readability is a mess
we can add a cleaning/renaming/moving function before or after the baking process but is very complicated and require "magic":
as a reference: https://github.com/pydanny/cookiecutter-django/blob/master/hooks/post_gen_project.py
this logic can be really helpful when you need not render specific files or directory
but not when you need to extend common configurations.
and somewhere at post gen hooks
Compatibility
This implementation is full retro compatible with already baked cookiecutter.
there are two main scenarios:
templatesdir: thetemplatesdirectory is optional, so no harm here.templatesdir: all keyword implemented have no sense before this implementation so that no one can use it, this means that thetemplateswill be loaded, but we can exclude the use.Questions and Discussion Topics
templatesis a too generic name?Let me know!