Skip to content

Code Generating Examples

Please checkout the tutorials for more thorough examples.

Simple generation example

# Render context
foo: bar

# Call generate hook
generate hook in compact form->: generate path/to/templates output/path
# Or
generate hook in expanded form:
  ->: generate
  templates: path/to/templates
  output: output/path

Sample Project Structure

For instance given this file structure:

├── templates
│ └── file1.py
│ └── file2.py
│ └──── dir
└── tackle.yaml

tackle.yaml

project_name->: input
project_slug->: input --default "{{project_name.lower()|replace(' ', '_')|replace('-', '_')|replace('.', '_')|trim()}}"
github_username->: input What is your Github username / org?
license->: select --choices ['apache','mit']
# or use the license hook
#license->: tackle robcxyz/tackle-license --output {{project_slug}}
postgres_version:
  ->: select
  choices:
    - 14
    - 13
    - 12
gen code->: generate templates {{project_slug}}

Would generate the following structure:

│ └── file1.py
│ └── file2.py
│ └──── dir
└── LICENSE

Using Remote Providers

Here is an example of how to use a license hook.

# project_slug is a standard name for your package directory
project_slug->: input What to call the project?
license->: tackle robcxyz/tackle-license --output {{project_slug}}
# project_slug is again used for other rendering outputs

Flow Control

use_docker->: confirm Do you want to use docker?
docker->:
  if: use_docker
  os:
    ->: select What docker base image?
    choices:
      - ubuntu
      - alpine
      - centos
  registry->: select Where to push docker image? --choices ['dockerhub','quay']
  generate dockerfile->: generate templates/Dockerfile {{project_slug}}/Dockerfile

# Use items inside block to render other templates
# For instance one could use {{docker.registry}} in a template
generate ci->: generate templates/.github {{project_slug}}

Another version of the same without a use_docker variable:

docker->:
  if: confirm('Do you want to use docker?')
  os->: select What docker base image? --choices ['ubuntu','alpine','centos']
  registry->: select Where to push docker image? --choices ['dockerhub','quay']
  generate dockerfile->: generate templates/Dockerfile {{project_slug}}/Dockerfile
generate ci->: generate templates/.github {{project_slug}}

Splitting up Context

Not specifically to code generation, but it is sometimes useful to have a sort of hierarchical layout with global variables. For instance:

child/tackle.yaml

context: tackle global.yaml --find_in_parent --merge

global.yaml

envs_>:
  dev:
    num_servers: 1 # etc...
  prod:
    num_servers: 2

# or in multiple lines / mix
environments:
  - prod
  - dev
env->: select --choices environments
merge it up a level with var hook->: var envs[env] --merge

Or all the above in one line->: var {{envs[select(choices=keys(envs))]}} --merge

Resulting in the following context

#? env >>> prod
environments:
- prod
- dev
env: prod
num_servers: 2

And then can be used to generate code or call CLIs wrapped with tackle such as kubectl.

Rendering in Segments

Segments of a code generation can be done ahead of time.

python_function_template: |
  {%for i in foo%}
  def {{i}}Function(x: int, y: int)
    print(x + y)
  {% endfor%}

python_function_rendered->: {{python_function_template}}

Which can then be further combined within the tackle file, rendered into a template, or updated within a file as described below.

Using the update_section Hook

Tackle can be used to update a section between two markers.

.tackle.yaml

update_readme<-:
  help: Update the README.md table
  exec:
    rows:
      - name: Stuff
        desc: A thing
      - name: Thing
        desc: A stuff
    update:
      ->: update_section README.md
      content: |
        | Name | Description |
        |---|---|
        {% for i in rows %}| {{i.name}} | {{i.desc}} |
        {% endfor %}

Running tackle update-readme

My App...

[//]: # (--start--)

| Name | Description |
|---|---|
| Stuff | A thing |
| Thing | A stuff |

[//]: # (--end--)

Does stuff