§ Reference · Commands

pravo validate, eval, fmt and gen

Check a specification without planning it, print its evaluated value, format the CUE files and regenerate the provider packages.

View as Markdown

On this page

Quick reference

Command Does Starts a provider Writes
pravo validate Evaluates the specification and checks it against the generated definitions. Prints a summary. no, once pravo init has cached the schema nothing
pravo eval Prints the evaluated value, as cue eval does. Fills in the recorded state. no nothing
pravo fmt Formats the .cue files of the current directory in place. no the files that change
pravo gen Rewrites the packages under cue.mod/gen from the cached schemas, and generates a package that an import names and that does not exist yet. no cue.mod/gen

validate and eval also work on plain CUE that declares no provider and imports no generated package. Imports of the CUE standard library are fine. The file needs a package clause, and no pravo init is needed. Taught in C4, eval and validate, A1, Your data is already CUE and B1, Providers and resources.

Flags

Flag Command Default Meaning
-e, --expression EXPR eval none Evaluate EXPR in the scope of the specification: a path such as logs.tags, or any CUE expression.
-c, --concrete eval off Fail unless every value is concrete.
-O, --optional eval off Print optional fields too.
-t, --tag key=value validate, eval, gen none Inject a value for an @tag() field. Repeatable.
-T, --inject-vars validate, eval, gen off Inject the system variables of CUE into tags written @tag(name,var=os).

fmt takes no flags of its own. The global flags apply. With --json, validate prints a document and the other three print text.

Exit codes

Code Command Meaning
0 all Done.
1 eval -c found a value that is not concrete, or -e is not an expression.
1 fmt A file does not parse.
1 all A flag is unknown, or an argument is given: these commands take none.
6 validate, eval, gen The specification does not load or evaluate. For validate also: a provider cannot be installed.

Every command that loads the specification reports the same errors with exit code 6.

Examples

Work in an empty directory named demo. The first file mixes a resource with plain CUE.

main.cue
package demo

import rnd "pravo.dev/providers/hashicorp/random"

$random: rnd.#Provider

base: $random.#Resource.random_integer & {min: 1, max: 9, seed: "base"}

size: int
size: 3
name: *"web" | string
port: int @tag(port,type=int)
tags: [for i in [1, 2, 3] {i * 2}]
settings: {
	region: "eu"
	zone?:  string
}
terminal
$pravo init > /dev/null

pravo validate

validate evaluates the specification and checks every resource against the definitions that pravo init generated. It catches a misspelt attribute, a wrong type, a missing reference and a violated constraint, with the file and the line. It also reports resources that depend on each other in a circle (see Errors). It does not run the validation of the providers themselves, which plan and apply do.

terminal
$pravo validate
Success! 1 resources, 0 data sources, 0 ephemeral, 0 function calls, 0 outputs across 1 providers.

The counts are resources, data sources, ephemeral resources, function calls, outputs and providers. A misspelt attribute is rejected before any provider starts. The block carries status=rejected.

typo.cuerejected
package demo

pet: $random.#Resource.random_pet & {lenght: 2}
terminalexit 6
$pravo validate
Error: evaluating .:
pet.lenght: field not allowed:
    ./typo.cue:3:38

The path is pet.lenght, the rule is field not allowed, and the location is the line of the attribute. Remove the file.

terminal
$rm typo.cue
$pravo validate --json
{
  "calls": 0,
  "data_sources": 0,
  "ephemeral": 0,
  "outputs": 0,
  "providers": 1,
  "resources": 1,
  "valid": true
}

A file without a package clause next to files that have one stops the load, and the error names the file:

loose/base.cue
package loose

size: 1
loose/loose.cue
size: 3
terminalexit 6
$pravo -C loose validate
Error: loading ./loose:
loose.cue has no package clause; the other files are package loose

When no file has a package clause, nothing loads:

terminalexit 6
$rm loose/base.cue
$pravo -C loose validate
Error: loading ./loose:
build constraints exclude all CUE files in .:
    ./loose/loose.cue: no package name

pravo eval

eval prints the specification after references are resolved, comprehensions expanded, constraints unified and defaults selected. A struct prints as the fields of a file. The recorded state of each resource is filled in.

terminal
$pravo eval | tail -n 9
	seed: "base"
}
size: 3
name: "web"
port: int
tags: [2, 4, 6]
settings: {
	region: "eu"
}

A field that is a type, not a value, prints as the type: port is int until a tag supplies it. -e selects a part:

terminal
$pravo eval -e size
$pravo eval -e name
$pravo eval -e 'tags[1]'
$pravo eval -e 'len(tags)'
$pravo eval -t port=8080 -e port
3
"web"
4
3
8080

-O prints the optional field zone?.

terminal
$pravo eval -e settings -O
region: "eu"
zone?:  string

-c fails when a value is not concrete. port has no value yet:

terminalexit 1
$pravo eval -c -e port
Error: the value is not concrete:
incomplete value int:
    ./main.cue:12:7

With the tag, the same command succeeds:

terminal
$pravo eval -t port=8080 -c -e port
8080

A computed attribute of a resource is incomplete until the resource is applied. After an apply, eval prints the recorded value.

terminal
$pravo eval -e base.result
$pravo apply -auto-approve > /dev/null
$pravo eval -e base.result
number | null
9

pravo fmt

fmt rewrites the .cue files of the current directory in the style of cue fmt. It prints the name of each file that changed and prints nothing for a file that is formatted. It does not descend into subdirectories.

messy.cue
package demo

x:   1


 y: {a:    2}
terminal
$pravo fmt
$pravo fmt
$cat messy.cue
messy.cue
package demo

x: 1

y: {a: 2}

pravo gen

gen rewrites every package under cue.mod/gen from the cached schemas of the providers in the lock file, and installs a provider that is missing. A package that an import names and that does not exist yet is generated first, as pravo init does.

Append a line to a generated file, and gen writes the file as it should be:

terminal
$echo "// edited" >> cue.mod/gen/pravo.dev/providers/hashicorp/random/random_gen.cue
$pravo gen
$pravo gen
Generated cue.mod/gen/pravo.dev/providers/hashicorp/random (10 resource types, 0 data sources, 2 ephemeral, 0 functions)
Up to date cue.mod/gen/pravo.dev/providers/hashicorp/random (10 resource types, 0 data sources, 2 ephemeral, 0 functions)

Each line names a package. Generated means the file changed, and Up to date means it is as gen writes it. Every other command that loads the specification warns when a generated package was made from another provider version than the one selected. init and gen write the package again and do not warn.

Remove the generated packages of the providers. gen generates the package that the import names:

terminal
$rm -r cue.mod/gen/pravo.dev/providers
$pravo gen
Configuration does not load yet; generating schemas for the declared providers first.
Generated cue.mod/gen/pravo.dev/providers/hashicorp/random (10 resource types, 0 data sources, 2 ephemeral, 0 functions)

See also