= CLI
include::ROOT:partial$component-attributes.adoc[]
:uri-homebrew: https://brew.sh

:uri-pkl-macos-amd64-download: {uri-maven-repo}/org/pkl-lang/pkl-cli-macos-amd64/{pkl-artifact-version}/pkl-cli-macos-amd64-{pkl-artifact-version}.bin
:uri-pkl-macos-aarch64-download: {uri-maven-repo}/org/pkl-lang/pkl-cli-macos-aarch64/{pkl-artifact-version}/pkl-cli-macos-aarch64-{pkl-artifact-version}.bin
:uri-pkl-linux-amd64-download: {uri-maven-repo}/org/pkl-lang/pkl-cli-linux-amd64/{pkl-artifact-version}/pkl-cli-linux-amd64-{pkl-artifact-version}.bin
:uri-pkl-linux-aarch64-download: {uri-maven-repo}/org/pkl-lang/pkl-cli-linux-aarch64/{pkl-artifact-version}/pkl-cli-linux-aarch64-{pkl-artifact-version}.bin
:uri-pkl-alpine-download: {uri-maven-repo}/org/pkl-lang/pkl-cli-alpine-linux-amd64/{pkl-artifact-version}/pkl-cli-alpine-linux-amd64-{pkl-artifact-version}.bin
:uri-pkl-java-download: https://repo1.maven.org/maven2/org/pkl-lang/pkl-cli-java/{pkl-artifact-version}/pkl-cli-java-{pkl-artifact-version}.jar

ifdef::is-release-version[]
:uri-pkl-macos-amd64-download: {github-releases}/pkl-macos-amd64
:uri-pkl-macos-aarch64-download: {github-releases}/pkl-macos-aarch64
:uri-pkl-linux-amd64-download: {github-releases}/pkl-linux-amd64
:uri-pkl-linux-aarch64-download: {github-releases}/pkl-linux-aarch64
:uri-pkl-alpine-download: {github-releases}/pkl-alpine-linux-amd64
:uri-pkl-java-download: {uri-maven-repo}/org/pkl-lang/pkl-cli-java/{pkl-artifact-version}/pkl-cli-java-{pkl-artifact-version}.jar
endif::[]

:uri-pkl-stdlib-docs-settings: {uri-pkl-stdlib-docs}/settings/
:uri-pkl-cli-main-sources: {uri-github-tree}/pkl-cli/src/main/kotlin/org/pkl/cli
:uri-pkl-cli-CliEvaluatorOptions: {uri-pkl-cli-main-sources}/CliEvaluatorOptions.kt
:uri-certificates: {uri-github-tree}/pkl-commons-cli/src/main/resources/org/pkl/commons/cli/commands

The `pkl` command-line interface (CLI) evaluates Pkl modules and writes their output to the console or a file.
For interactive development, the CLI includes a Read-Eval-Print Loop (REPL).

[[installation]]
== Installation

The CLI comes in multiple flavors:

* Native macOS executable for amd64 (tested on macOS 10.15)
* Native Linux executable for amd64 (tested on Oracle Linux 8)
* Native Linux executable for aarch64 (tested on Oracle Linux 8)
* Native Alpine Linux executable for amd64 (cross-compiled and tested on Oracle Linux 8)
* Java executable (tested with Java 8/11/14 on macOS and Oracle Linux)

On macOS and Linux, we recommend using the native executables.
They are self-contained, start up instantly, and run complex Pkl code much faster than the Java executable.

.What is the Difference Between the Linux and Alpine Linux Executables?
[NOTE]
====
The Linux executable is dynamically linked against _glibc_ and _libstdc{plus}{plus}_,
whereas, the Alpine Linux executable is statically linked against _musl libc_ and _libstdc{plus}{plus}_.
====

The Java executable works on multiple platforms and has a smaller binary size than the native executables.
However, it requires a Java 8 (or higher) runtime on the system path, has a noticeable startup delay,
and runs complex Pkl code slower than the native executables.

All flavors are built from the same codebase and undergo the same automated testing.
Except where noted otherwise, the rest of this page discusses the native executables.

//TODO uncomment this after brew formula is merged and available
// [[homebrew]]
// === Homebrew
// 
// Release versions can be installed with {uri-homebrew}[Homebrew].
// 
// ifdef::is-release-version[]
// To install Pkl, run:
// 
// [source,shell]
// ----
// brew install pkl
// ----
// 
// To update Pkl, run:
// 
// [source,shell]
// ----
// brew update
// brew upgrade pkl   # or just `brew upgrade`
// ----
// endif::[]
// 
// ifndef::is-release-version[]
// For instructions, switch to a release version of this page.
// endif::[]

[[download]]
=== Download

Development and release versions can be downloaded and installed manually.

=== macOS Executable

On aarch64:

[source,shell]
[subs="+attributes"]
----
curl -L -o pkl {uri-pkl-macos-aarch64-download}
chmod +x pkl
./pkl --version
----

On amd64:

[source,shell]
[subs="+attributes"]
----
curl -L -o pkl {uri-pkl-macos-amd64-download}
chmod +x pkl
./pkl --version
----

This should print something similar to:

[source,shell]
[subs="+attributes"]
----
Pkl {pkl-version} (macOS, native)
----

[[linux-executable]]
=== Linux Executable

The Linux executable is dynamically linked against _glibc_ and _libstdc{plus}{plus}_ for the amd64 and aarch64 architectures.
For a statically linked executable, see <<Alpine Linux Executable>>.

On aarch64:

[source,shell]
[subs="+attributes"]
----
curl -L -o pkl {uri-pkl-linux-aarch64-download}
chmod +x pkl
./pkl --version
----

On amd64:

[source,shell]
[subs="+attributes"]
----
curl -L -o pkl {uri-pkl-linux-amd64-download}
chmod +x pkl
./pkl --version
----

This should print something similar to:

[source,shell]
[subs="+attributes"]
----
Pkl {pkl-version} (Linux, native)
----

[[alpine-linux-executable]]
=== Alpine Linux Executable

The Alpine Linux executable is statically linked against _musl libc_ and _libstdc{plus}{plus}_.
For a dynamically linked executable, see <<Linux Executable>>.

[source,shell]
[subs="+attributes"]
----
curl -L -o pkl {uri-pkl-alpine-download}
chmod +x pkl
./pkl --version
----

This should print something similar to:

[source,shell]
[subs="+attributes"]
----
Pkl {pkl-version} (Linux, native)
----

NOTE: We currently do not support the aarch64 architecture for Alpine Linux.

=== Java Executable

[source,shell]
[subs="+attributes"]
----
curl -L -o jpkl {uri-pkl-java-download}
chmod +x jpkl
./jpkl --version
----

This should print something similar to:

[source,shell]
[subs="+attributes"]
----
Pkl {pkl-version} (macOS 10.16, Java 11.0.9)
----

[[usage]]
== Usage

*Synopsis:* `pkl <subcommand> [<options>] [<args>]`

For a brief description of available options, run `pkl -h`.

NOTE: The Java executable is named `jpkl`.

[[command-eval]]
=== `pkl eval`

*Synopsis:* `pkl eval [<options>] [<modules>]`

Evaluate the given Pkl `<modules>` and produce their rendering results.

<modules>::
The absolute or relative URIs of the modules to evaluate.
Relative URIs are resolved against the working directory.

==== Options

[[format]]
.-f, --format
[%collapsible]
====
Default: (none) +
Example: `yaml` +
The output format to generate.
The default output renderer for a module supports the following formats:

* `json`
* `jsonnet`
* `pcf`
* `plist`
* `properties`
* `textproto`
* `xml`
* `yaml`

If no format is set, the default renderer chooses `pcf`.
====

[[output-path]]
.-o, --output-path
[%collapsible]
====
Default: (none) +
Example: "config.yaml" +
The file path where the output file is placed.
Relative paths are resolved against the project directory.

// suppress inspection "AsciiDocLinkResolve"
This option is mutually exclusive with link:#multiple-file-output-path[`--multiple-file-output-path`].
If neither option is set, each module's `output.text` is written to standard output.

If multiple source modules are given, placeholders can be used to map them to different output files.
The following placeholders are supported:

`%\{moduleDir}`:::
The directory path of the module, relative to the working directory.
Only available when evaluating file-based modules.

`%\{moduleName}`:::
The simple module name as inferred from the module URI.
For hierarchical URIs such as `+file:///foo/bar/baz.pkl+`, this is the last path segment without file extension.

`%\{outputFormat}`:::
The requested output format.
Only available if `--format` is set.

If multiple source modules are mapped to the same output file, their outputs are concatenated.
By default, module outputs are separated with `---`, as in a YAML stream.
// suppress inspection "AsciiDocLinkResolve"
The separator can be customized using the link:#module-output-separator[`--module-output-separator`] option.
====

[[module-output-separator]]
.--module-output-separator
[%collapsible]
====
Default: `---` (as in a YAML stream) +
The separator to use when multiple module outputs are written to the same file, or to standard output.
====

[[multiple-file-output-path]]
.-m, --multiple-file-output-path
[%collapsible]
====
Default: (none) +
Example: "output/" +
The directory where a module's output files are placed.

Setting this option causes Pkl to evaluate a module's `output.files` property
and write the files specified therein.
Within `output.files`, a key determines a file's path relative to `--multiple-file-output-path`,
and a value determines the file's contents.

// suppress inspection "AsciiDocLinkResolve"
This option cannot be used together with any of the following:

* xref:output-path[`--output-path`]
* xref:expression[`--expression`]

// suppress inspection "AsciiDocLinkResolve"
This option supports the same placeholders as link:#output-path[`--output-path`].

Examples:

[source,shell]
----
# Write files to `output/`
pkl eval -m output/ myFiles.pkl

# Write files to the current working directory
pkl eval -m . myFiles.pkl

# Write foo.pkl's files to the `foo` directory, and bar.pkl's files
# to the `bar` directory
pkl eval -m "%{moduleName}" foo.pkl bar.pkl
----

For additional details, see xref:language-reference:index.adoc#multiple-file-output[Multiple File Output] 
in the language reference.
====

[[expression]]
.-x, --expression
[%collapsible]
====
Default: (none) +
The expression to be evaluated within the module.

This option causes Pkl to evaluate the provided expression instead of the module's `output.text` or `output.files` properties.
The resulting value is then stringified, and written to either standard out, or the designated output file.

For example, consider the following Pkl module:

.pigeon.pkl
[source%tested,{pkl}]
----
metadata {
  species = "Pigeon"
}
----

The following command prints `Pigeon` to the console:

[source,shell]
----
pkl eval -x metadata.species pigeon.pkl
# => Pigeon
----

Setting an `--expression` flag can be thought of as substituting the expression in place of a module's `output.text` property.
Running the previous command is conceptually the same as if the below module were evaluated without the `--expression` flag:

[source,pkl]
----
metadata {
  species = "Pigeon"
}

output {
  text = metadata.species.toString()
}
----
====

This command also takes <<common-options, common options>>.

[[command-server]]
=== `pkl server`

*Synopsys:* `pkl server`

Run as a server that communicates over standard input/output.

This option is used for embedding Pkl in an external client, such as xref:swift:ROOT:index.adoc[pkl-swift] or xref:go:ROOT:index.adoc[pkl-go].

[[command-test]]
=== `pkl test`

*Synopsys:* `pkl test [<options>] [<modules>]`

Evaluate the given `<modules>` as _tests_, producing a test report and appropriate exit code.

Renderers defined in test files will be ignored by the `test` command.

<modules>::
The absolute or relative URIs of the modules to test. Relative URIs are resolved against the working directory.

==== Options

[[junit-reports]]
.--junit-reports
[%collapsible]
====
Default: (none) +
Example: `./build/test-results` +
Directory where to store JUnit reports.

No JUnit reports will be generated if this option is not present.
====

[[overwrite]]
.--overwrite
[%collapsible]
====
Force generation of expected examples. +
The old expected files will be deleted if present.
====

This command also takes <<common-options, common options>>.

[[command-repl]]
=== `pkl repl`

*Synopsys:* `pkl repl [<options>]`

Start a REPL session.

This command takes <<common-options, common options>>.

[[command-project-package]]
=== `pkl project package`

*Synopsis:* `pkl project package <project-dir>`

This command prepares a project to be published as a package.
Given a project directory, it creates the following artifacts:

* `<name>@<version>` - the package metadata file
* `<name>@<version>.sha256` - the dependency metadata file's SHA-256 checksum
* `<name>@<version>.zip` - the package archive
* `<name>@<version>.zip.sha256` - the package archive's SHA-256 checksum

These artifacts are expected to be published to an HTTPS server, such that the metadata and zip files can be fetched at their expected locations.

The package ZIP should be available at the `packageZipUrl` location specified in the `PklProject` file
The package metadata should be available at the package URI's derived HTTPS URL.
For example, given package `package://example.com/mypackage@1.0.0`, the metadata file should be published to `+https://example.com/mypackage@1.0.0+`.

During packaging, this command runs these additional steps:

1. Run the package's API tests, if any are defined.
2. Validates that if the package has already been published, that the package's metadata is identical. This step can be skipped using the `--skip-publish-check` flag.

Examples:

[source,shell]
----
# Search the current working directory for a project, and package it.
pkl project package

# Package all projects within the `packages/` directory to `.out`, writing each package's artifacts to its own directory.
pkl project package --output-path ".out/%{name}@%{version}/" packages/*/
----

==== Options

.--output-path
[%collapsible]
====
Default: `.out`

The directory to write artifacts to.
Accepts the following placeholders:

`%\{name}`:: The name of the package
`%\{version}`:: The version of the package
====

.--skip-publish-check
[%collapsible]
====
Skips checking whether a package has already been published with different contents.

By default, the packager will check whether a package at the same version has already been published.
If the package has been published, it validates that the package's metadata is identical to the locally generated metadata.
====

.--junit-reports
[%collapsible]
====
Default: (none) +
Example: `./build/test-results` +
Directory where to store JUnit reports.

No JUnit reports will be generated if this option is not present.
====

.--overwrite
[%collapsible]
====
Force generation of expected examples. +
The old expected files will be deleted if present.
====

This command also takes <<common-options,common options>>.

[[command-project-resolve]]
=== `pkl project resolve`

*Synopsis:* `pkl project resolve <project-dir>`

This command takes the dependencies of a project, and writes the resolved versions a file at path `PklProject.deps.json`.

It builds a dependency list, taking the latest minor version in case of version conflicts.
For more details, see the xref:language-reference:index.adoc#resolving-dependencies[resolving dependencies] section of the language reference.

Examples:
[source,shell]
----
# Search the current working directory for a project, and resolve its dependencies.
pkl project resolve

# Resolve dependencies for all projects within the `packages/` directory.
pkl project resolve packages/*/
----

==== Options

This command accepts <<common-options,common options>>.

[[command-download-package]]
=== `pkl download-package`

*Synopsis*: `pkl download-package <package-uri>`

This command downloads the specified packages to the cache directory.
If the
package already exists in the cache directory, this command is a no-op.

==== Options

This command accepts <<common-options,common options>>.

[[common-options]]
=== Common options

The <<command-eval>>, <<command-test>>, <<command-repl>>, <<command-project-resolve>>, <<command-project-package>>, and <<command-download-package>> commands support the following common options:

include::../../pkl-cli/partials/cli-common-options.adoc[]

The <<command-eval>>, <<command-test>>, <<command-repl>>, and <<command-download-package>> commands also take the following options:

include::../../pkl-cli/partials/cli-project-options.adoc[]

== Evaluating Modules

Say we have the following module:

[[config.pkl]]
.config.pkl
[source,{pkl}]
----
bird {
  species = "Pigeon"
  diet = "Seeds"
}
parrot = (bird) {
  species = "Parrot"
  diet = "Berries"
}
----

To evaluate this module and write its output to standard output, run:

[source,shell]
----
pkl eval config.pkl
----

You should see the following output:

[source,{pkl}]
----
bird {
  species = "Pigeon"
  diet = "Seeds"
}
parrot {
  species = "Parrot"
  diet = "Berries"
}
----

To render output as JSON, YAML, XML property list, or Java properties,
use `--format json`, `--format yaml`, `--format plist`, or `--format properties`, respectively.

To control the output format from within Pkl code, see xref:language-reference:index.adoc#module-output[Module Output].

To read a source module from standard input rather than a file, use `-` as a module name:

[source,shell]
----
echo mod2.pkl | pkl eval mod1.pkl - mod3.pkl
----

This is especially useful in environments that don't support `/dev/stdin`.

To write output to a file rather than standard output, use `--output-path some/file.ext`.

[[batch-evaluation]]
=== Batch Evaluation

Multiple modules can be evaluated at once:

[source,shell]
----
pkl eval config1.pkl config2.pkl config3.pkl
----

To write module outputs to separate output files, `--output-path` supports the following placeholders:

`%\{moduleDir}`:: the directory path of the source module, relative to the working directory (only available for file based modules)
`%\{moduleName}`:: the last path segment of the module URI, without file extension
`%\{outputFormat}`:: the target format (only available if `--format` is set)

The following run produces three JSON files placed next to the given source modules:

[source,shell]
----
pkl eval --format=json --output-path=%{moduleDir}/%{moduleName}.json config1.pkl config2.pkl config3.pkl
----

If multiple module outputs are written to the same file, or to standard output, their outputs are concatenated.
By default, module outputs are separated with `---`, as in a YAML stream.
The separator can be customized using the `--module-output-separator` option.

[[repl]]
== Working with the REPL

To start a REPL session, run `pkl repl`:

[source,shell]
[subs="+attributes"]
----
$ pkl repl
Welcome to Pkl {pkl-version}.
Type an expression to have it evaluated.
Type :help or :examples for more information.

pkl>
----

NOTE: The Java executable is named `jpkl`.

=== Loading Modules

To load <<config.pkl,`config.pkl`>> into the REPL, run:

[source,shell]
----
pkl> :load config.pkl
----

To evaluate the `bird.species` property, run:

[source,shell]
----
pkl> bird.species
"Pigeon"
----

To evaluate the entire module, force-evaluate `this`:

[source,shell]
----
pkl> :force this
----

=== REPL Commands

Commands start with `:` and can be tab-completed:

[source,shell]
[subs="+attributes,+macros"]
----
pkl> :{empty}kbd:[Tab]
clear       examples    force       help        load        quit        reset
pkl> :q{empty}kbd:[Tab]
pkl> :quit{empty}kbd:[Return]
$
----

Commands can be abbreviated with any unique name prefix:

[source,shell]
[subs="+attributes,+macros"]
----
pkl> :q{empty}kbd:[Return]
$
----

To learn more about each command, run the `:help` command.

Some commands support further command-specific tab completion.
For example, the `:load` command supports completing file paths.

With commands out of the way, let's move on to evaluating code.

=== Evaluating Code

To evaluate an expression, type the expression and hit kbd:[Return].

[source,shell]
----
pkl> 2 + 4
6
----

Apart from expressions, the REPL also accepts property, function, and class definitions.
(See the xref:language-reference:index.adoc[Language Reference] to learn more about these language concepts.)

[source,shell]
----
pkl> hello = "Hello, World!"
pkl> hello
"Hello, World!"
pkl> function double(n) = 2 * n
pkl> double(5)
10
pkl> class Bird { species: String }
pkl> new Bird { species = "Pigeon" }
{
  name = ?
}
----

Top-level expressions are only supported in the REPL.
In a regular module, every expression is contained in a definition, and only definitions exist at the top level.

=== Redefining Members

Existing members can be redefined:

[source,shell]
----
pkl> species = "Pigeon"
pkl> species
"Pigeon"
pkl> species = "Barn"
pkl> species
"Barn"
pkl> species + " Owl"
pkl> species
"Barn Owl"
----

Due to Pkl's late binding semantics, redefining a member affects dependent members:

[source,shell]
----
pkl> name = "Barn"
pkl> species = "\(name) Owl"
pkl> species
"Barn Owl"
pkl> name = "Elf"
pkl> species
"Elf Owl"
----

Redefining members is only supported in the REPL. Under the hood,
it works as follows:

* The REPL environment is represented as a synthetic Pkl module.
* When a new member is defined, it is added to the current REPL module.
* When an existing member is redefined, it is added to a new REPL module that xref:language-reference:index.adoc#module-amend[amends] the previous REPL module.

[[settings-file]]
== Settings File

The Pkl settings file allows to customize the CLI experience.

A settings file is a Pkl module amending the `pkl.settings` standard library module.
Its default location is `~/.pkl/settings.pkl`.
To use a different settings file, set the `--settings` command line option, for example `--settings mysettings.pkl`.
To enforce default settings, use `--settings pkl:settings`.
The settings file is also honored by (and configurable through) the Gradle plugin and `CliEvaluator` API.

Here is a typical settings file:

.~/.pkl/settings.pkl
[source%parsed,{pkl}]
----
amends "pkl:settings" // <1>

editor = Idea // <2>
----
<1> A settings file should amend the `pkl.settings` standard library module.
<2> Configures IntelliJ IDEA as the preferred editor.
Other supported values are `System`, `GoLand`, `TextMate`, `Sublime`, `Atom`, and `VsCode`.

With the above settings file in place, kbd:[Cmd]+Double-clicking a source code link in a stack trace opens the corresponding file in IntelliJ IDEA at the correct location.

To learn more about available settings, see link:{uri-pkl-stdlib-docs-settings}[pkl.settings].

[[ca-certs]]
== CA Certificates

When making TLS requests, Pkl comes with its own set of {uri-certificates}[CA certificates].
These certificates can be overridden via either of the two options:

- Set them directly via the CLI option `--ca-certificates <path>`.
- Add them to a directory at path `~/.pkl/cacerts/`.

Both these options will *replace* the default CA certificates bundled with Pkl. +
The CLI option takes precedence over the certificates in `~/.pkl/cacerts/`. +
Certificates need to be X.509 certificates in PEM format.
