CLI Reference
Eucalypt is available as a command line tool, eu, which reads inputs
and writes outputs.
Everything it does in between is purely functional and there is no mutable state.
It is intended to be simple to use in unix pipelines.
eu --version # shows the current eu version
eu --help # lists command line options
Command Structure
The eu command uses a subcommand structure for clarity and extensibility:
eu [GLOBAL_OPTIONS] [SUBCOMMAND] [SUBCOMMAND_OPTIONS] [FILES...]
Subcommands
run(default) - Evaluate eucalypt codetest- Run testsdump- Dump intermediate representationsversion- Show version informationexplain- Explain what would be executedlist-targets- List targets defined in the sourcefmt- Format eucalypt source fileslsp- Start the Language Server Protocol server
When no subcommand is specified, run is used by default, so these are equivalent:
eu file.eu
eu run file.eu
Inputs
Files / stdin
eu can read several inputs, specified by command line arguments.
Inputs specify text data from:
- files
- stdin
- internal resources (ignored for now)
- (in future) HTTPS URLs or Git refs
...of which the first two are the common case. In the simplest case,
file inputs are specified by file name, stdin is specified by -.
So
eu a.yaml - b.eu
...will read input from a.yaml, stdin and b.eu.
Each will be read into eucalypt's core representation and merged
before output is rendered.
Input format
Inputs must be one of the formats that eucalypt supports, which at present, are:
- yaml
- json
- jsonl (JSON Lines)
- toml
- edn
- xml
- csv
- text
Of these yaml, json, toml, edn and xml return blocks; jsonl, csv and text return lists. Inputs that return lists frequently need to be named (see below) to allow them to be used.
Usually the format is inferred from file extension but it can be
overridden on an input by input basis using a format@ prefix.
For instance:
eu yaml@a.txt json@- yaml@b.txt
...will read YAML from a.txt, JSON from stdin and YAML from b.txt.
Named inputs
Finally inputs can be named using a name= prefix. This alters the
way that data is merged by making the contents of an input available
in a block or list with the specified name, instead of at the top
level.
Suppose we have two inputs:
foo: bar
x: 42
then
eu a.yaml b.eu
would generate:
foo: bar
x: 42
but
eu data=a.yaml b.eu
would generate:
data:
foo: bar
x: 42
This can be useful for various reasons, particularly when:
- the form of the input's content is not known in advance
- the input's content is a list rather than a block
Full input syntax
The full input syntax is therefore:
[name=][format@][URL/file]
This applies at the command line and also when specifying
imports in .eu files.
stdin defaulting
When no inputs are specified and eu is being used in a pipeline, it
will accept input from stdin by default, making it easy to pipe JSON
or YAML from other tools into eu.
For example, this takes JSON from the aws CLI and formats it as YAML
to stdout.
aws s3-api list-buckets | eu
How inputs are merged
When several inputs are listed, names from earlier inputs become available to later inputs, but the content that will be rendered is that of the final input.
So for instance:
a.eu
x: 4
y: 8
b.eu
z: x + y
eu a.eu b.eu
will output
z: 12
The common use cases are:
- a final input containing logic to inspect or process data provided by previous inputs
- a final input which uses functions defined in earlier inputs to process data provided in previous inputs
If you want to render contents of earlier inputs, you need a named input to provide a name for that content which you can then use.
For instance:
eu r=a.eu b.eu -e r
will render:
x: 4
y: 8
--collect-as and --name-inputs
Occasionally it is useful to aggregate data from an arbitrary number of sources files, typically specified by shell wildcards. To refer to this data we need to introduce a name for the collection of data.
This is what the command line switch --collect-as / -c is for.
eu --collect-as inputs *.eu
...will render:
inputs:
- x: 4
y: 8
- z: 12
It is common to use -e to select an item to render:
eu -c inputs *.eu -e 'inputs head'
...renders:
x: 4
y: 8
If you are likely to need to refer to inputs by name, you can add
--name-inputs / -N to pass inputs as a block instead of a list:
eu --collect-as inputs --name-inputs *.eu
...renders:
inputs:
a.eu:
x: 4
y: 8
b.eu:
z: 12
This makes it easier to invoke specific functions from named inputs
although you will need single-quote name syntax to use the generated
names which contain .s.
Outputs
In the current version, eu can only generate one output.
Output format
Output is rendered as YAML by default. Other formats can be specified
using the -x command line option:
eu -x json # for JSON
eu -x text # for plain text
JSON is such a common case that there is a shortcut: -j.
Output targets
By default, eucalypt renders all the content of the final input to output.
There are various ways to override this. First, :target metadata can
be specified in the final input to identify different parts for
potential export.
To list the targets found in the specified inputs, use the
list-targets subcommand.
eu list-targets file.eu
...and a particular target can be selected for render using -t.
eu -t my-target
If there is a target called "main" it will be used by default unless another target is specified.
Evaluands
In addition to inputs, an evaluand can be specified at the command line. This is a eucalypt expression which has access to all names defined in the inputs and replaces the input body or targets as the data to export.
It can be used to select content or derive values from data in the inputs:
$ aws s3api list-buckets | eu -e 'Buckets map(lookup(:CreationDate)) head'
2016-12-25T14:22:30.000Z
...or just to test out short expressions or command line features:
$ eu -e '{a: 1 b: 2 * 2}' -j
{"a": 1, "b": 4}
Passing Arguments to Programs
You can pass command-line arguments to your eucalypt program using the
-- separator. Arguments after -- are available via io.args:
$ eu -e 'io.args' -- foo bar baz
---
- foo
- bar
- baz
This is useful for writing eucalypt scripts that accept parameters:
# greet.eu
name: io.args head-or("World")
greeting: "Hello, {name}!"
$ eu greet.eu -e greeting -- Alice
---
Hello, Alice!
Arguments are passed as strings. Use num to convert numeric arguments:
# sum.eu
total: io.args map(num) foldl((+), 0)
$ eu sum.eu -e total -- 1 2 3 4 5
---
15
When no arguments are passed, io.args is an empty list:
$ eu -e 'io.args nil?'
---
true
Random Seed
By default, random numbers are seeded from system entropy and produce
different results on each run. Use --seed for reproducible output:
eu --seed 42 template.eu
This sets io.RANDOM_SEED and seeds the io.random stream. See
Random Numbers for the full random API.
IO Monad Operations
By default, eucalypt is a pure functional language with no side effects. To
enable IO monad operations — specifically shell command execution — you must
pass the --allow-io / -I flag:
eu -I script.eu
eu --allow-io script.eu
Without this flag, any program that attempts to execute an IO action will fail with an error:
IO operations require the --allow-io (-I) flag
Why this flag exists
The flag is a deliberate security measure. Eucalypt files are often used as
configuration or data templates, and it would be unsafe for arbitrary .eu
files loaded from the filesystem or network to execute shell commands without
explicit consent. The --allow-io flag is your explicit acknowledgement that
the program you are running may perform shell execution.
Usage with IO targets
IO programmes typically use the :io monadic block syntax and are run with a
named target:
eu -I --target main script.eu
eu -I -t main script.eu
See the IO monad design documentation for full details of the IO API.
Suppressing prelude
A standard prelude containing many functions and operators is automatically prepended to the input list.
This can be suppressed using -Q if it is not required or if you
would like to provide an alternative.
Warning: Many very basic facilities -- like the definition of
trueandfalseandif-- are provided by the prelude so suppressing it leaves a very bare environment.
Debugging
eu has a variety of command line switches for dumping out internal
representations or tracing execution. The dump subcommand provides
access to intermediate representations:
eu dump ast file.eu # Parse and dump syntax tree
eu dump desugared file.eu # Dump core expression
eu dump stg file.eu # Dump compiled STG syntax
eu list-targets file.eu # List available targets
Use eu --help and eu <subcommand> --help for complete option lists.
Formatting Source Files
The fmt subcommand formats eucalypt source files for consistent style:
eu fmt file.eu # Print formatted output to stdout
eu fmt --write file.eu # Format in place
eu fmt --check file.eu # Check formatting (exit 1 if not formatted)
eu fmt *.eu --write # Format multiple files in place
Options
-w, --width <WIDTH>- Line width for formatting (default: 80)--write- Modify files in place--check- Check if files are formatted (exit 1 if not)--reformat- Full reformatting mode (instead of conservative)--indent <INDENT>- Indent size in spaces (default: 2)
The formatter has two modes:
- Conservative mode (default) - Preserves original formatting choices where possible, only reformatting where necessary
- Reformat mode (
--reformat) - Full reformatting that applies consistent style throughout
Language Server Protocol
The lsp subcommand starts an LSP server for use with editors that
support the Language Server Protocol (e.g., VS Code, Neovim):
eu lsp
The LSP server provides:
- Syntax error diagnostics
- Formatting support (via
textDocument/formatting)
Configure your editor to use eu lsp as the language server command
for .eu files. A VS Code extension is available in the editors/vscode/
directory of the repository.
Version Assertions
The eu.requires function allows eucalypt source files to assert a
minimum version of the eucalypt executable:
{ import: [] } # unit-level metadata not required for eu.requires
# Assert that eu version satisfies semver constraint
_ : eu.requires(">=0.3.0")
If the running version of eu does not satisfy the constraint, an
error is raised immediately. This is useful for library code that
depends on features introduced in a particular version.
The eu namespace also provides build metadata:
version: eu.build.version # e.g., "0.3.0"
Backward Compatibility
All existing command patterns continue to work unchanged:
eu file.eu # Still works (uses run subcommand)
eu -e "expression" # Still works (uses run subcommand)
eu -j file.eu # Still works (JSON output)
eu -S -Q file.eu # Still works (statistics, no prelude)