yutc is a templating command line interface written in (surprise, surprise) Go.
It is designed to parse and merge data files (YAML, JSON, TOML), and apply them to templates.
The application supports reading data from both local files and URLs,
and can output the results to a file or stdout.
Download the latest build or any other version from the releases page. Put it somewhere on your computer. Add it to your path. If you are using this you probably already know how to do that.
You can use yutc by passing it a list of templates along with various options:
Usage:
yutc [flags] <template_files...>
yutc is a command line tool for rendering complex templates from arbitrary sources.
Data & Templates:
--allow-shell Enable the 'shell' template function (execute arbitrary shell commands - use with caution)
--auth string Authentication for any URL source. Format: 'user:pass' for Basic Auth or 'token' for Bearer Token.
-c, --common-templates stringArray Templates to be shared across all arguments in template list. Can be a file or a URL. Can be specified multiple times.
-d, --data stringArray Data file to parse and merge. Can be a file or a URL. Can be specified multiple times and the inputs will be merged. Optionally nest data under a top-level key using: jsonpath=<path>,src=<path> See --help=syntax for more details.
--helm Enable Helm-specific data processing (Convert keys specified with key=Chart to pascalcase)
--include-filenames Process filenames as templates
--set stringArray Set a data value via a key path. Can be specified multiple times.
Output & Rendering:
--drop-extension string Drop file extension from output filename before outputting (default "tmpl")
--ignore-empty Skip writing empty rendered template output to output location
-o, --output string Output file/directory, defaults to stdout (default "-")
-w, --overwrite Overwrite existing files
--strict On missing value, throw error instead of zero
System:
-h, --help Show help. A topic may be specified as --help=<topic>.
Available topics:
syntax Syntax for advanced file arguments and options
-v, --verbose Verbose output
--version Print the version and exit
toYaml is a custom template function that converts the input to a yaml representation.
similar to the toYaml in helm.
mustToYaml is also available, which will panic if the input cannot be converted to yaml.
{{ . | toYaml }}
fromYaml is a custom template function that converts the input to a go object.
similar to the fromYaml in helm.
mustFromYaml is also available, which will panic if the input cannot be converted to a go object.
{{ fromYaml . | .SomeField | toString }}
yamlOptions allows you to set options for the yaml encoder. These settings will be global across all calls
to toYaml and mustToYaml. See the documentation for goccy/go-yaml for details.
DecodeOption support will be added in the future.
{{ yamlOptions (dict "indent" 2) }}
{{ toYaml $someData }}
wrapText uses textwrap to wrap text to a specified width.
wrapComment is a wrapper around wrapText that adds a comment character to the beginning of each line.
{{ wrapText 80 .SomeText }}
{{ wrapComment "#" 80 .SomeText }}
toToml is a custom template function that converts the input to a TOML representation.
Similar to toYaml but for TOML format.
mustToToml is also available, which will panic if the input cannot be converted to TOML.
{{ . | toToml }}
fromToml is a custom template function that converts TOML input to a go object.
Similar to fromYaml but for TOML format.
mustFromToml is also available, which will panic if the input cannot be converted to a go object.
{{ fromToml . | .SomeField | toString }}
fileGlob - Returns a list of files matching a glob pattern.
fileStat - Returns file statistics as a map with keys like Mode, Size, ModTime, etc.
fileRead - Reads the entire contents of a file as a string.
fileReadN - Reads the first N bytes of a file as a string.
{{- range fileGlob "*.txt" }}
File: {{ . }}
{{- end }}
{{- $stat := fileStat "myfile.txt" }}
Size: {{ $stat.Size }} bytes
{{ fileRead "config.txt" }}
{{ fileReadN 100 "largefile.txt" }}
pathAbsolute - Returns the absolute path of the given path.
pathIsDir - Returns true if the path is a directory.
pathIsFile - Returns true if the path is a file.
pathExists - Returns true if the path exists.
{{ pathAbsolute "./relative/path" }}
{{- if pathExists "myfile.txt" }}
{{- if pathIsFile "myfile.txt" }}
File exists: {{ pathAbsolute "myfile.txt" }}
{{- end }}
{{- end }}
{{- if pathIsDir "mydirectory" }}
Directory found!
{{- end }}
type returns the Go type of the given value as a string.
{{ type . }}
{{ type "hello" }}
{{ type 42 }}
sortList sorts a list of values and returns a new sorted list. Supports strings, integers, and float64 values.
The original list is not modified.
{{- $unsorted := list "zebra" "apple" "banana" }}
{{- range sortList $unsorted }}
- {{ . }}
{{- end }}
{{- $numbers := list 3 1 4 1 5 9 2 6 }}
Sorted: {{ sortList $numbers }}
sortKeys returns a new map with keys sorted alphabetically. Useful for consistent output ordering,
especially when generating YAML or other formats where key order matters.
{{- $config := dict "zebra" 1 "apple" 2 "banana" 3 }}
{{- range $key, $value := sortKeys $config }}
{{ $key }}: {{ $value }}
{{- end }}
jsonPathQuery returns data from an object using a JSONPath expression.
Paths may start with . or $.
{{ jsonPathQuery . "$.app.name" }}
{{ jsonPathQuery . ".items[0]" }}
These helpers escape content for JavaScript, HTML, or URL query contexts, pulled from the htmltemplate package.
{{ escapeJs .userInput }}
{{ escapeHtml .description }}
{{ escapeUrlQuery .searchTerm }}
shell executes an arbitrary shell command and returns its stdout as a string.
Requires --allow-shell to be passed at the CLI — the function is not registered otherwise.
Uses powershell -Command on Windows and sh -c on Unix.
{{ shell "echo hello" }}
{{ shell "git rev-parse --short HEAD" }}
include allows you to include and render other templates as text within the current template.
This is the exact same as the include function in Helm.
{{ include "shared-template" . }}
tpl, also from Helm
{{ tpl $my_template . }}
a file
yutc -o patch.yaml \
-d ./talosPatches/controlplane-workloads.yaml \
-d talosPatches/disable-cni.yaml \
-d talosPatches/disable-discovery.yaml \
-d talosPatches/install-disk.yaml \
-d talosPatches/kubelet.yaml \
-d talosPatches/local-storage.yaml \
-d talosPatches/names.yaml \
<(echo "{{ . | toYaml }}")alternate form using matching
yutc -o patch.yaml \
--data ./talosPatches \
<(echo "{{ . | toYaml }}")For some reason you want to list the files in a directory and embed them in a file in a custom format:
{{- $files := fileGlob "./*/*" -}}
{{- range $path := $files }}
{{- $stat := fileStat $path }}
{{- $username := (env "USERNAME" | default (env "USER") )}}
{{- $usernameFString := printf "%s%d%s " "%-" (len $username) "s"}}
{{ printf "%-12s" $stat.Mode }}{{ printf $usernameFString $username }}{{ pathAbsolute $path}}
{{- end }}
-rw-rw-rw- adam C:\Users\adam\code\yet-unnamed-template-cli\.git\COMMIT_EDITMSG
-rw-rw-rw- adam C:\Users\adam\code\yet-unnamed-template-cli\.git\FETCH_HEAD
-rw-rw-rw- adam C:\Users\adam\code\yet-unnamed-template-cli\.git\HEAD
-rw-rw-rw- adam C:\Users\adam\code\yet-unnamed-template-cli\.git\ORIG_HEAD
-rw-rw-rw- adam C:\Users\adam\code\yet-unnamed-template-cli\.git\config
-rw-rw-rw- adam C:\Users\adam\code\yet-unnamed-template-cli\.git\description
drwxrwxrwx adam C:\Users\adam\code\yet-unnamed-template-cli\.git\hooks
........
yutc --data .\testFiles\data\data1.yaml --data .\testFiles\data\data2.yaml .\testFiles\templates\simpleTemplate.tmplJSON representation of the merged input:
---
{
"ditto": [
"woohooo",
"yipeee"
],
"dogs": [],
"thisIsNew": 1000,
"thisWillMerge": {
"value23": 23,
"value24": 24
}
}
---
Yaml representation:
---
ditto:
- woohooo
- yipeee
dogs: []
thisIsNew: 1000
thisWillMerge:
value23: 23
value24: 24
---
yutc --data "jsonpath=.data1,src=./testFiles/data/data1.yaml" \
--data "jsonpath=.data2,src=./testFiles/data/data3.json" \
./testFiles/templates/simpleTemplate.tmplWe see below that we are able to specify a key for each data file, and the data is not merged at the top level.
Unmerged data from data 1: {"dogs":[{"breed":"Labrador","name":"Fido","owner":{"name":"John Doe"},"vaccinations":["rabies"]}],"thisWillMerge":{"value23":"not 23","value24":24}}
Unmerged data from data 2: {"ditto":["woohooo","yipeee"],"dogs":[],"thisIsNew":1000,"thisWillMerge":{"value23":23}}
You can set individual data values directly from the command line using JSONPath syntax:
# Set simple values
yutc --set '$.version=1.2.3' --set '$.name=myapp' template.tmpl
# Convenience: paths starting with . are auto-prefixed with $
yutc --set '.version=1.2.3' --set '.name=myapp' template.tmpl
# Set nested values
yutc --set '.config.database.host=localhost' \
--set '.config.database.port=5432' \
template.tmpl
# Override values from data files
yutc -d config.yaml --set '.env=production' template.tmpl
# Set arrays and objects (JSON format)
yutc --set '.ports=[8080,8443]' \
--set '.metadata={"author":"me","version":"1.0"}' \
template.tmplNote on value types: Values are parsed as JSON when possible, otherwise treated as strings.
--set '.count=42'sets a number--set '.count="42"'sets a string--set '.name=foo'sets the string "foo" (quotes not required for simple strings)--set '.enabled=true'sets a boolean--set '.items=[1,2,3]'sets an array of numbers--set '.config={"key":"value"}'sets an object
You can load JSON Schema documents via --data by using a structured argument with type=schema. Schemas are applied after all data is merged.
yutc \
--data ./testFiles/data/data1.yaml \
--data "src=./testFiles/schemas/person.yaml,type=schema" \
./testFiles/templates/simpleTemplate.tmplWhen rendering multiple templates, you often want to remove a suffix like .tmpl from the output filenames.
# If you have:
# templates/config.yaml.tmpl
# templates/deployment.yaml.tmpl
#
# This command will produce:
# dist/config.yaml
# dist/deployment.yaml
yutc -o ./dist/ --drop-extension tmpl ./templates/*.tmplYou can provide authentication globally or per-source.
# Global authentication for all URL sources
yutc --auth "my-token" -d https://api.example.com/data.yaml ./template.tmpl
# Per-source authentication using structured arguments
yutc -d "src=https://api.example.com/data.yaml,auth=user:pass" ./template.tmplSee README.data.yaml and README.md.tmpl for the source data and template
I had very specific requirements that gomplate, gucci, and others weren't quite able to meet. Both of those a great apps, and if you So really i just made this for myself at my day-job, but if anyone else finds it useful, here it is. Enjoy those specific features!
The name yutc is a acronym of yet-unnamed-template-cli,
which i guess is now in fact named.