Executors

< Selectors Fields >

What are executors?

Executors are built-in terp types that can be used to run an application. terp provides the basic process executor type under the ^exec() alias. terp does not enforce any restrictions on the applications that can be executed via this wrapper. If you are security conscious, you should limit terp's ability to execute arbitrary code via the normal Java security mechanisms (policy files and/or security managers).

All executors can be initialized using a map of name/value pairs. Supported name/value pairs are listed in the table below.

^exec() initialization aattributes
Name Description
environment Optional. A collection of strings representing name=value environment settings. When not specified, the caller's environment is inherited.
executable Required. Path to the executable. Should be fully qualified name including filename extension (if applicable to platform).
libpath Optional. A path that will be prepended to the platform's library search path environment variable or, if none is defined, added as the value of the platform's library search path environment variable. The name of the environment variable is derived from the operating system's envVarLibrarySearchPath trait and is usually a string like "LD_LIBRARY_PATH" or similar.
workingdir Optional. The directory set as the present working directory for the process. When not specified, the caller's working directory is inherited.

You can use these settings in the following way:

^exec({executable:'/opt/SUNWspro/bin/CC', workingdir:'/home/alex'})

In the above snippet, we specify a SUN C++ compiler as the application we wish to run and the user's home directory as the present working directory in which to run it.

API representation

Custom executors typically extend the ProcessExecutor or the ShellExecutor class.

How do I invoke an executor?

Every executor is invoked by adding parenthesized arguments to it, for example:

^exec({executable:'/opt/SUNWspro/bin/CC'})('-V')

Please note the difference between the first set of parentheses that encloses the initializers and the second set of parentheses that encloses the call arguments. To pass multiple arguments, simply separate them by commata:

^exec({executable:'/usr/bin/g++'})('--help', '-v')

How do I retrieve executor results?

Executors always return an instance of built-in type ProcessExecutor.Result. A result object has the following properties:

^exec() result properties
Name Description
exitcode The return value of the command. By convention most executables return 0 to represent success and non-0 values for errors or warnings..
out The array of text lines written to stdout.
outraw The raw output, including linebreak characters.
err The array of text lines written to stderr.
errraw The raw error output, including linebreak characters.

Shell executors

Not all commands that you wish to execute are available as executable programs. Some only exist as shell commands, shell scripts, or batch files that need to be run in a command shell. terp supports such use cases via a ^shell() executor. ^shell() supports all ^exec() initialization options plus two additional settings that are listed below.

^shell() additional initialization attributes
Name Description
shell Optional. Allows you to specify the shell you want to use. See below for default value.
environment Optional. Specify a collection or a map of environment options. You can also use prefixes of add. or remove. for variable names to modify the existing environment.
execflag Optional. The command switch that tells the shell that the following argument is a shell command that should be executed and then the shell should be terminated.

Please note that the shell attribute does not map to the inherited executable attribute. This is because ^shell() derived executors usually use the executable property for other purposes. You normally don't have to provide any initialization arguments to ^shell() because the terp runtime sets everything up for you. terp uses the following heuristics to select a shell:

  • Windows: query COMSPEC environment variable. If not found, use C:/Windows/System32/cmd.exe.
  • Others: query SHELL environment variable. If not found, use following search order: /bin/bash, /bin/tcsh, /bin/sh.

You can override the default heuristics by initializing the shell instance manually, for example:

myshell = ^shell({shell:'/bin/tcsh', execflag:'/c'})

Please note the assignment of the executor to a variable. You don't always have to create a new executor instance for every invocation. Once you have an instance, you can assign it to a variable and reuse it from there.

Sometimes you want to use the calling process' environment with a few modifications. This is easy to achieve by using the environment override with the add or remove modifiers. In the following snippet we remove the XMOG_HOME environment variable (if it is there) and add the FOOBAR variable to the environment.

myshell = ^shell({ environment:{remove.XMOG_HOME:'dummy', add.FOOBAR:'test'  } })	    

Let's look at an example to illustrate the usage of the ^shell() executor. To get a directory listing on a Windows system, you usually type the dir command. Using a shell executor to get the listing for the present working directory, you could simply write:

^shell()('dir')

or to get the listing for the parent directory:

^shell()('dir ..')

Special Executors

terp supplies additional executors that wrap commonly used development tools like ANT and C++ development tools. Most special purpose executors are derived from the shell executor rather than the basic process executor. This is due to the fact that many tools are invoked through launcher scripts or batch files or require the execution of a batch file before their executables can be invoked successfully. The special purpose executors account for all these idiosyncracies and save you the work of figuring it out yourself.

Please revisit the above examples of C++ compiler invocations. Consider the simplified invocation when using the ^gcc() compiler executor:

^gcc('/usr/bin/g++')('--help', '-v')

If you were happy with terp's default choice for g++ compiler, you could further simplify to:

^gcc()('--help', '-v')

This would work because the ^gcc() executor has special heuristics for locating g++ compilers. You can see how the special executors add significant value. Each of the special executors has a customization that allows it to be smart about its specific purpose. Usually, the customization consists simply of the ability to locate the executable without the user having to specify anything. The executor instantiation will resolve to null if no executable can be located.

If you wanted to find out the supported targets of the QNX Neutrino compiler (qcc), you could evaluate the following expression:

^qcc()('-V')

The following table contains the special-purpose, built-in terp executors.

built-in executors
Name Description
^acc HP ANSI C++ compiler executor.
^ant ANT executor.
^ar Unix ar (archive) utility executor.
^bc BoundsChecker executor.
^cpp Generic C++ compiler executor.
^gcc GNU C++ compiler executor.
^gprof GNU profiler executor.
^icc Intel C++ compiler executor.
^java Java executor.
^javac Java compiler executor.
^javadoc Javadoc compiler executor.
^jar Jar tool executor.
^juggernet Code generator executor (set up wit a -dotnet option).
^junction Code generator executor (set up with a -cpp option)..
^lib Microsoft library maintenance utility.
^msvc Microsoft Visual C++ compiler executor.
^qcc QNX Neutrino C++ compiler executor.
^reg Microsoft Windows Registry utility executor.
^regquery Microsoft Windows Registry utilityquery executor.
^suncc SUN Workshop C++ compiler executor.
^rc Microsoft resource compiler.
^xlc IBM VisualAge C++ compiler executor.

All of the C++ executors support initialization/configuration from a variety of inputs, all listed here.

Details on built-in Executors

This section provides non-obvious facts and details on several of the built-in executors.

^java()

Every java executor instance is related to a Java Runtime Environment (jre) instance to which it belongs. You can go from one to the other via ^java().jre or ^jre().java. The jre type provides access to the built-in system classpath, for example:

C:\terp\bin>terp "^java().jre.systemclasspath[join(eol)]"
/usr/jdk/jdk1.6.0_14/jre/lib/jce.jar
/usr/jdk/jdk1.6.0_14/jre/lib/plugin.jar
/usr/jdk/jdk1.6.0_14/jre/lib/management-agent.jar
/usr/jdk/jdk1.6.0_14/jre/lib/resources.jar
/usr/jdk/jdk1.6.0_14/jre/lib/javaws.jar
/usr/jdk/jdk1.6.0_14/jre/lib/alt-rt.jar
/usr/jdk/jdk1.6.0_14/jre/lib/deploy.jar
/usr/jdk/jdk1.6.0_14/jre/lib/rt.jar
/usr/jdk/jdk1.6.0_14/jre/lib/jsse.jar
/usr/jdk/jdk1.6.0_14/jre/lib/charsets.jar
C:\terp\bin>

^javac()

Every javac (Java compiler) executor instance is related to a Java Development Kit (jdk) instance to which it belongs. You can go from one to the other via ^javac().jdk or ^jdk().javac. The jdk type provides access to its corresponding jre, a tools classpath, and a java executor.


Copyright 2006-2013 by Codemesh, Inc., ALL RIGHTS RESERVED

:
terp expressions
codemesh.com home expressions templates ant about us contact us download   

Commandline