When developing assistants, please make sure that you read proper version of documentation. The Yaml DSL of devassistant is still evolving rapidly, so consider yourself warned.
This is a reference manual to writing yaml assistants. Yaml assistants use a special DSL defined on this page. For real examples, have a look at assistants in our Github repo.
There are three types of assistants:
The role is implied by assistant location in one of the load path directories, as mentioned in Assistants Loading Mechanism.
All the rules mentioned in this document apply to all types of assistants, with exception of sections Modifier Assistants and Preparer Assistants that talk about specifics of Modifier, resp. Preparer assistants.
Assistant name is a short name used on command line, e.g. python. It should also be the only top-level yaml mapping in the file (that means just one assistant per file). Each assistant should be placed in a file that’s named the same as the assistant itself (e.g. python assistant in python.yaml file).
The top level mapping has to be mapping from assistant name to assistant attributes, for example:
python:
fullname: Python
# etc.
List of allowed attributes follows (all of them are optional, and have some sort of reasonable default, it’s up to your consideration which of them to use):
Yaml assistants can express their dependencies in multiple sections.
Packages from section dependencies are always installed.
If there is a section named dependencies_foo, then dependencies from this section are installed iff foo argument is used (either via commandline or via gui). For example:
$ da python --foo
These rules differ for Modifier Assistants
Each section contains a list of mappings dependency type: [list, of, deps]. If you provide more mappings like this:
dependencies:
- rpm: [foo]
- rpm: ["@bar"]
they will be traversed and installed one by one. Supported dependency types:
installs dependencies from snippet or other dependency section of this assistant. For example:
dependencies:
- call: foo # will install dependencies from snippet "foo", section "dependencies"
- call: foo.dependencies_bar # will install dependencies from snippet "foo", section "bar"
- call: self.dependencies_baz # will install dependencies from section "dependencies_baz" of this assistant
conditional dependency installation. For more info on conditions, Run below. A very simple example:
dependencies:
- if $foo:
- rpm: [bar]
- else:
- rpm: [spam]
Full example:
dependencies: - rpm: [foo, "@bar"]
dependencies_spam:
- rpm: [beans, eggs]
- if $with_spam:
- call: spam.spamspam
- rpm: [ham]
Arguments are used for specifying commandline arguments or gui inputs. Every assistant can have zero to multiple arguments.
The args section of each yaml assistant is a mapping of arguments to their attributes:
args:
name:
flags:
- -n
- --name
help: Name of the project to create.
Available argument attributes:
GUI needs to work with arguments dynamically, choose proper widgets and offer sensible default values to user. These are not always automatically retrieveable from arguments that suffice for commandline. For example, GUI cannot meaningfully prefill argument that says it “defaults to current working directory”. Also, it cannot tell whether to choose a widget for path (with the “Browse ...” button) or just a plain text field.
Because of that, each argument can have gui_hints attribute. This can specify that this argument is of certain type (path/str/bool) and has a certain default. If not specified in gui_hints, the default is taken from the argument itself, if not even there, a sensible “empty” default value is used (home directory/empty string/false). For example:
args:
path:
flags:
- [-p, --path]
gui_hints:
type: path
default: $(pwd)/foo
If you want your assistant to work properly with GUI, it is good to use gui_hints (currently, it only makes sense to use it for path attributes, as str and bool get proper widgets and default values automatically).
This section serves as a list of aliases of files stored in one of the files dirs of DevAssistant. E.g. if your assistant is assistants/crt/foo/bar.yaml, then files are taken relative to files/crt/foo/bar/ directory. So if you have a file files/crt/foo/bar/spam, you can use:
files:
spam: &spam
source: spam
This will allow you to reference the spam file in run section as *spam without having to know where exactly it is located in your installation of DevAssistant.
Run sections are the essence of DevAssistant. They are responsible for preforming all the tasks and actions to set up the environment and the project itself. By default, section named run is invoked (this is a bit different for Modifier Assistants). If there is a section named run_foo and foo argument is used, then only run_foo is invoked. This is different from dependencies sections, as the default dependencies section is used every time.
Every run section is a sequence of various commands, mostly invocations of commandline. Each command is a mapping command_type: command. During the execution, you may use logging (messages will be printed to terminal or gui) with following levels: DEBUG, INFO, WARNING, ERROR, CRITICAL. By default, messages of level INFO and higher are logged. As you can see below, there is a separate log_* command type for logging, but some other command types can also log various messages. Log messages with levels ERROR and CRITICAL terminate execution of DevAssistant imediatelly.
Run sections allow you to use variables with certain rules and limitations. See below.
List of supported commands follows:
run a whole section in SCL environment of one or more SCLs (note: you must use the scriptlet name - usually enable - because it might vary) - for example:
run:
- scl enable python33 postgresql92:
- cl_i: python --version
- cl_i: pgsql --version
Initially, variables are populated with values of arguments from commandline/gui and there are no other variables defined for creator assistants. For modifier assistants global variables are prepopulated with some values read from .devassistant. You can either define (and assign to) your own variables or change the values of current ones.
The variable scope works as follows:
All variables are global in the sense that if you call a snippet or another section, it can see all the arguments that are defined.
Expressions are expressions, really. They are used in assignments, conditions and as loop “iterables”. Every expression has a logical result (meaning success - True or failure - False) and result (meaning output). Logical result is used in conditions and variable assignments, result is used in variable assignments and loops. Note: when assigned to a variable, the logical result of an expression can be used in conditions as expected; the result is either True/False.
Syntax and semantics:
When using variables that contain user input, they should always be quoted in the places where they are used for bash execution. That includes cl* commands, conditions that use bash return values and variable assignment that uses bash.
Modifier assistants are assistants that are supposed to work with already created project. They must be placed under mod subdirectory of one of the load paths, as mentioned in Assistants Loading Mechanism.
There are few special things about modifier assistants:
Preparer assistants are assistants that are supposed to set up environment for executing arbitrary tasks or prepare environment and checkout existing upstream projects (possibly using their .devassistant file, if they have it). Preparers must be placed under prep subdirectory of one of the load paths, as mentioned in Assistants Loading Mechanism.
Preparer assistants commonly utilize the dda_dependencies and dda_run commands in run section.