At the start of lets application, parser tries to find
lets.yaml file starting from current directory up to the
When config file is found, parser tries to read/parse and validate yaml config.
Lets has feature called mixins. When parser meets
it basically repeats all read/parse logic on minix files.
Since mixin config files have some limitations, although they are parsed the same way, validation is a bit different.
config.go:Config struct implements
UnmarshalYAML function, so when
yaml.Unmarshal called with
Config instance passed in,
custom unmarshalling code is executed.
Its common to make some normalization of commands and its data during parsing phase so the rest of the code does not have to do any kind of normalization on its own.
There are two validation phases.
First validation phase happens during unmarshalling and checks if:
- directives names valid
- directives types valid (array, map, string, number, etc.)
- references to command in
dependsdirective points to existing commands
Second phase happens after we ensured that config is syntactically and semantically correct.
Int the second phase we are checking:
- config version
- circular dependencies in commands
We are using
Cobra CLI framework and delegating to it most of the work related to parsing
command line arguments, help messages etc.
Now we have to bind our config to
Cobra has a concept of
cobra.Command. It is a representation of command in CLI application, for example:
git is a CLI applications and
pull are commands.
In a traditional
lets application commands will be what is declared in
lets.yaml commands section.
To achieve this we are creating so-called
root command and
subcommands from config.
Root command is responsible for:
letsown command line flags such as
--helpand so on.
letscommands autocompletion in terminal
Subcommand is created from our
RunE callback we are parsing/validation/normalizing command line arguments for this subcommand
and then finally executing command with
Since we are using
docopt as an argument parser for subcommands, we don't let
Cobra parse and interpret args,
and instead we are passing raw arguments as is to
Runner is responsible for:
- parsing and preparing args using
- calculating and storing command's checksums
- executing other commands from
- preparing environment
- running command in OS using