Run Configurations
Introduction
Run configurations allow you to define how to execute programs, written in your language.
An existing run configuration can be executed either from run configurations box, located on the main toolbar,
by the "Run" menu item in the main menu
or through the run/debug popup (Alt+Shift+F10/Alt+Shift+F9).
Also run configurations could be executed/created for nodes, models, modules and project. For example, JUnit run configuration could run all tests in selected project, module or model. See Run configurations creators on how to implement such behavior for you run configurations.
To summarize, run configurations define the following things:
- On creation stage:
- configurations name, caption, icon;
- configurations kind;
- how to create a configuration from node(s), model(s), module(s), project.
- On configuration stage:
- persistent parameters;
- editor for persistent parameters;
- checker of persistent parameters validity.
- On execution stage:
- proccess which is actually executed;
- console with all its tabs, action buttons and actual console window;
- things required for debugging this configuration (if it is possible).
The following languages are introduced in MPS 2.0 to support run configurations in MPS.
jetbrains.mps.execution.common
(common language) – contains concepts utilized by the other execution* languages;jetbrains.mps.execution.settings
(settings language) – language for defining different setting editors;jetbrains.mps.execution.commands
(command languages) – processes invocation from java;jetbrains.mps.execution.configurations
(configurations language) – run configurations definition;
Settings
Settings language allows to create setting editors and integrate them into one another. What we need from settings editor is the following:
- fields to edit;
- validation of fields correctness;
- editor UI component;
- apply/reset functions to apply settings from UI component and to reset settings in the UI component to the saved state;
- dispose function to destroy UI component when it is no longer needed.
As you can see, settings have UI components. Usually, one UI component is created for multiple instances of settings. In the settings language settings are usually called "configurations" and their UI components are called "editors".
The main concept of settings language is PersistentConfigurationTemplate
. It has the following sections:
- persistent properties. This section describes the actual settings we are editing. Since we want also to persist this settings (i.e. to write to xml/read from xml) and to clone our configurations there is a restriction on their type: each property should be either
Cloneable
orString
or any primitive type. There is also a special kind of property namedtemplate persistent property
, but they are going to be discussed later. - editor. This section describes the editor of the configuration. It has functions
create
,apply to
,reset from
,dispose
. Section also can define fields to store some objects in the editor.create
function should return a swing component – the main UI component of the editor.apply to
/reset from
functions apply or reset settings in the editor to/from configuration given as a parameter.dispose
function disposes the editor. - check. In this section persistent properties are checked for correctness. If some properties are not valid, a
report error
statement can be used. Essentially, this statement throwsRuntimeConfigurationException
. - additional methods. This section is for methods, used in the configurations. Essentially, this methods are configuration instance methods.
Persistent properties
It was said above that persistent properties could be either Cloneable
or String
or any primitive type. But if one uses settings language inside run configurations, those properties should also support xml persistent. Strings and primitives are persisted as usual. For objects persistent is more complicated. Two types of properties are persisted for an object: public instance fields and properties with setXXX and getXXX methods. So, if one wish to use some complex type in persistent property, he should either make all important field public or provide setXXX and getXXX for whatever he wants to persist.
Integrating configurations into one another
One of the two basic features of settings language is the ability to easy integration of one configuration into another. For that template persistent properties
are used.
Template parameters
The second basic feature of settings language is template parameters. These are like constructor parameters in java. for example, if one creates a configuration for choosing a node, he may want to parametrize the configuration with nodes concept. The concept is not a persistent parameter in this case: it is not chosen by the user. This is a parameter specified on configuration creation.
Commands
Commands language allows to start up processes from the code in a way it is done from command line. The main concept of the language is CommandDeclaration
. In the declaration, command parameters and the way to start process with this parameters are specified. Also, commands can have debugger parameters and some utility methods.
Execute command sections
Each command can have several execute
sections. Each of this sections defines several execution parameters. There are parameters of two types: required and optional. Optional parameters can have default values and could be ommited when the command is started, while required can not have default values and are mandatory. Two execute sections of the command should have different (by types) lists of required parameters. One execute section can invoke another execute section. Each execute section should return either values of process
or ProcessHandler
types.
ProcessBuilderExpression
To start a process from a command execute section ProcessBuilderExpression
isused. It is a simple list of command parts. Each part is either ProcessBuilderPart
which consists of an expression of type string
or list<string>
, or a ProcessBuilderKeyPart
which represents a parameter with a key (like "-classpath /path/to/classes"). When the code generated from ProcessBuilderExpression
is invoked, each part is tested for being null or empty and ommited if so. Then, each part is splitted into many parts by spaces. So if you would like to provide a command part with a space in it and do not wish it to be splitted (for example, you have a file path with spaces), you have to put it into double quotes ("). Working directory of created process could be specified in inspector.
Debugger integration
To integrate a command with the debugger, two things are required to be specified:
- the specific debugger to integrate with;
- the command line arguments for a process.
To specify a debugger one can useDebuggerReference
– an expression ofdebugger
type injetbrains.mps.debug.apiLang
– to reference a specific debugger. Debugger settings must be an object of typeIDebuggerSettings
.
Configurations
Configurations language allows to create run configurations. To create a run configuration, on should create an instance of RunConfiguration
(essentially, configuration from settings language) and provide a RunConfigurationExecutor
for it. One also may need a RunConfigurationKind
to specify a kind of this configuration, RunConfigurationProducer
to provide a way of creating this configuration from nodes, models, modules etc and a BeforeTask
to specify how to prepare a configuration before execution.
Executors
Executor is a node which describes how a process is started for this run configuration. It takes settings user entered and created a process from it. So, the executor's execute methods should return an instance of type process
. This is done via StartProcessHandlerStatement
. Anything which has type process
or ProcessHandler
could be passed to it. A process
could be created in three different ways:
- via command;
- via
ProcessBuilderExpression
(recommended to use in commands only); - by creating new instance of ProcessHandler class; this method is recommended only if the above two do not fit you, for example when you creating a run configuration for remote debug and do not really need to start a process.
The executor itself consists of the following sections:
- "for" section where the configuration this executor is for and an alias for it is specified;
- "can" section where the ability of run/debug this configuration is specified; if the command is not used in this executor, one must provide an instance of
DebuggerConfiguration
here; - "before" section with the call of tasks which could be executed before this configuration run, such as Make;
- "execute" section where the process itself is created.
Debugger integration
If a command is used to start a process, nothing should be done apart from specifying a configuration as debuggable (by selecting "debug" in the executor). However, if a custom debugger integration is required, it is done the same way as in command declaration.
Useful examples
In this section you can find some useful tips and examples of run configurations usages.
Person Editor
In this example a editor for a "Person" is created. This editor edits two properties of a person: name and e-mail address.
PersonEditor could be used from java code in the following way:
Exec command
This is an example of a simple command which starts a given executable
with programParameters
in a given workingDirectory
. You can find this example in model jetbrains.mps.samples.nanoc.plugin
in project nanocProject
in MPS samples.
Compile with gcc before task
This is anexample of a BeforeTask
wich does compilation of a source file with gcc
command. It also demonstrates how to use commands outside of run configurations executors.
Note that this is just a toy example, in real life one should show a progress window while compiling.
Java Executor
This is an actual executor of Java run configuration from MPS.
Running a node, generated into java class
Lets suppose you have a node of a concept which is generated into a java class with a main method and you wish to run this node from MPS. Then you do not have to create a run confgiuration in this case, but you should do the following:
- The concept you wish to run should implement
IMainClass
concept fromjetbrains.mps.execution.util
language. To specify when the node can be executed, overrideisNodeRunnable
method. - Unit information should be generated for the concept. Unit information is required to correctly determine the class name which is to be executed. You can read more about unit information, as whell as about all trace information, in Debugger section of MPS documentation. To ensure this check that one of the following conditions are satisfied:
- a
ClassConcept
fromjetbrains.mps.baseLanguage
is generated from the node; - a node is generated into text (the language uses
textGen
aspect for generation) and the concept of the node implementsUnitConcept
interface fromjetbrains.mps.traceable
; - a node is genearted into a concept for which one of the three specified conditions is satisfied.
- a
1 Comment
Anonymous
Wait, I cannot fahtom it being so straightforward.