Skip to content

Modular Code Generation

Code generation can be made modular by calling other code generating tackle providers which can be either remote or local or breaking up how to read in context.

Using Tackle Providers

One of the main reasons tackle was originally made was to build modular code generators. The vision is that there will be a few, well crafted tackle providers to create different sections of boilerplate which can be easily updated over time. A good example of boilerplate is a license file which this snippet can call.

# 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

Which will prompt you such as below:

? What to call the project? MyApp
❯ Apache 2.0
  MIT
  GPL Version 3
  BSD Version 3
  Closed source
? Who are the license holders? Me
? What year to end the license? 2022

This provider can also be called from the command line:

tackle robcxyz/tackle-license

Which also comes with a nice help screen:

tackle robcxyz/tackle-license help

Hopefully over time, providers will be created that specialize in certain files / aspects of code and people can then stitch together templates more easily.

Tackle provider versions

By default, tackle uses the latest github released version unless there is not official release in which case it uses the version in the default branch. Fortunately there is a way to pin the version of an imported tackle with the checkout flag which under the hood, is performing a git checkout command to get the proper version of the code. For instance:

# Use the latest version in the default branch
latest->: tackle robcxyz/tackle-provider --latest
# If the branch was main, the following would be the same
branch->: tackle robcxyz/tackle-provider --checkout main
# Best practice is to pin to some versioned release  
pinned->: tackle robcxyz/tackle-provider --checkout v0.1.0

Groups of tackle providers

If one wanted to run a number of providers:

providers:
  ->: checkbox What additional items do you want to add to the generated code?
  checked: true
  choices:
    - license
    - makefile
    - pre-commit

call providers->: tackle robcxyz/tackle-{{item}} --for providers

Since the output of a checkbox is a list, it can be used as the input to the for key and since it is a string, it is rendered by default.

Splitting up Context

Sometimes you want to break up your business logic or build hierarchical ways of merging config files, one could have a pattern such as:

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

This allows for lots of dev ops related code generation patterns in conjunction with other tools such as kubectl which tackle can wrap.

Next Tutorials