Heredocs

Heredocs let you quote strings with more control over escaping, interpolation, and formatting. They’re especially good for long strings with complicated content.

Example

$gitconfig = @("GITCONFIG"/L)
    [user]
        name = ${displayname}
        email = ${email}
    [color]
        ui = true
    [alias]
        lg = "log --pretty=format:'%C(yellow)%h%C(reset) %s \
    %C(cyan)%cr%C(reset) %C(blue)%an%C(reset) %C(green)%d%C(reset)' --graph"
        wdiff = diff --word-diff=color --ignore-space-at-eol \
    --word-diff-regex='[[:alnum:]]+|[^[:space:][:alnum:]]+'
    [merge]
        defaultToUpstream = true
    [push]
        default = upstream
    | GITCONFIG

file { "${homedir}/.gitconfig":
  ensure  => file,
  content => $gitconfig,
}

Syntax

To write a heredoc, you place a heredoc tag in a line of code. This tag acts as a literal string value, but the content of that string is read from the lines that follow it. The string ends when an end marker is reached.

The general form of a heredoc string is:

heredoc tag

@("ENDTEXT"/<X>)

You can use a heredoc tag in Puppet code, anywhere a string value is accepted. In the above example, the heredoc tag @("GITCONFIG"/L) completes the line of Puppet code: $gitconfig = .

A heredoc tag starts with @( and ends with ).

Between those characters, the heredoc tag contains end text (see below) — text that is used to mark the end of the string. You can optionally surround this end text with double quotation marks to enable interpolation (see below). In the above example, the end text is GITCONFIG.

It also optionally contains escape switches (see below), which start with a slash /. In the above example, the heredoc tag has the escape switch /L.

the string

This is the
text that makes
up my string.

The content of the string starts on the next line, and can run over multiple lines. If you specified escape switches in the heredoc tag, the string can contain the enabled escape sequences.

In the above example, the string starts with [user] and ends with default = upstream. It uses the escape sequence \ to add cosmetic line breaks, because the heredoc tag contained the /L escape switch.

end marker

 | - ENDTEXT

On a line of its own, the end marker consists of:

  • Optional indentation and a pipe character (|) to indicate how much indentation is stripped from the lines of the string (see below).

  • An optional hyphen character (-), with any amount of space around it, to trim the final line break from the string (see below).

  • The end text, repeating the same end text used in the heredoc tag, always without quotation marks.

In the above example, the end marker is | GITCONFIG.

If a line of code includes more than one heredoc tag, Puppet reads all of those heredocs in order: the first one begins on the following line and continue until its end marker, the second one begins on the line immediately after the first end marker, and so on. Puppet won’t start evaluating additional lines of Puppet code until it reaches the end marker for the final heredoc tag from the original line.

End text

The heredoc tag contains piece of text called the end text. When Puppet reaches a line that contains only that end text (plus optional formatting control), the string ends.

Both occurrences of the end text must match exactly, with the same capitalization and internal spacing.

End text can be any run of text that doesn’t include line breaks, colons, slashes, or parentheses. It can include spaces, and can be mixed case. The following are all valid end text:

  • EOT

  • ...end...end...

  • Verse 8 of The Raven

To help with code readability, make your end text stand out from the content of the heredoc string, for example, by making it all uppercase.

Enabling interpolation

By default, heredocs do not allow you to interpolate values into the string content. You can enable interpolation by double-quoting the end text in the opening heredoc tag. That is:

  • An opening tag like @(EOT) won’t allow interpolation.

  • An opening tag like @("EOT") allows interpolation.

If you enable interpolation, but the string has a dollar character ($) that you want to be literal, not interpolated, you must enable the literal dollar sign escape switch (/$) in the heredoc tag: @("EOT"/$). Then use the escape sequence \$ to specify the literal dollar sign in the string. See the information on enabling escape sequences, below, for more details.

Enabling escape sequences

By default, heredocs have no escape sequences and every character is literal (except interpolated expressions, if enabled). To enable escape sequences, add switches to the heredoc tag.

To enable individual escape sequences, add a slash (/) and one or more switches. For example, to enable an escape sequence for dollar signs (\$) and new lines (\n), add /$n to the heredoc tag :

@("EOT"/$n)

To enable all escape sequences, add a slash and no switches:

@("EOT"/)

Use the following switches to enable escape sequences:

Switch to put in the heredoc tagEscape sequence to use in the heredoc stringResult in the string value
(automatic)\\Single backslash. This switch is enabled when any other escape sequence is enabled.
n\nNew line
r\rCarriage return
t\tTab
s\sSpace
$\$Literal dollar sign (to prevent interpolation)
u\uXXXX or \u{XXXXXX}Unicode character number XXXX (a four-digit hexadecimal number) or XXXXXX (a two- to six-digit hexadecimal number)
L\<New line or carriage return>Nothing. This lets you put line breaks in the heredoc source code that does not appear in the string value.
A backslash that isn't part of an escape sequence is treated as a literal backslash. Unlike in double-quoted strings, this does not log a warning.

If a heredoc has escapes enabled, and includes several literal backslashes in a row, make sure each literal backslash is represented by the \\ escape sequence. So, for example, If you want the result to include a double backslash, use four backslashes.

Enabling syntax checking

To enable syntax checking of heredoc text, add the name of the syntax to the heredoc tag. For example:

@(END:pp)
@(END:epp)
@(END:json)

If Puppet has a syntax checker for the given syntax, it validates the heredoc text, but only if the heredoc is static text and does not contain any interpolations. If Puppet has no checker available for the given syntax, it silently ignores the syntax tag.

Syntax checking in heredocs is useful for validating syntax earlier, avoiding later failure.

By default, heredocs are treated as text unless otherwise specified in the heredoc tag.

Stripping indentation

To make your code easier to read, you can indent the content of a heredoc to separate it from the surrounding code. To strip this indentation from the resulting string value, put the same amount of indentation in front of the end marker and use a pipe character (|) to indicate the position of the first “real” character on each line.

$mytext = @(EOT)
    This block of text is
    visibly separated from
    everything around it.
    | EOT
If a line has less indentation than you’ve indicated with the pipe, Puppet strips any spaces it can without deleting non-space characters.

If a line has more indentation than you’ve indicated with the pipe, the excess spaces are included in the final string value.

Indentation can include tab characters, but Puppet won’t convert tabs to spaces, so make sure you use the exact same sequence of space and tab characters on each line.

Suppressing literal line breaks

If you enable the L escape switch, you can end a line with a backslash (\) to exclude the following line break from the string value. This lets you break up long lines in your source code without adding unwanted literal line breaks to the resulting string value.

For example, Puppet would read this as a single line:

lg = "log --pretty=format:'%C(yellow)%h%C(reset) %s \
%C(cyan)%cr%C(reset) %C(blue)%an%C(reset) %C(green)%d%C(reset)' --graph"

Suppressing the final line break

By default, heredocs end with a trailing line break, but you can exclude this line break from the final string. To suppress it, add a hyphen (-) to the end marker, before the end text, but after the indentation pipe if you used one. This works even if you don’t have the L escape switch enabled.

For example, Puppet would read this as a string with no line break at the end:

$mytext = @("EOT")
    This is too inconvenient for ${double} or ${single} quotes, but must be one line.
    |-EOT