Script Extensions

About Script Extensions

A script extension can be used as a library with a collection of objects, variables and functions. BPS itself contains several script extensions, for example bps and bps.gui which are documented for public use, bps.audit, bps.installer etc which are used internally by bps itself, and samples amd samples.reports as simple examples.

Technically extensions can be written as c++ plugin, as plain script or as a combination thereof. The bps and bps.gui are examples of extensions combined by a c++ plugin (plugins\script\bpsscript.dll and plugins\script\bpsscrgui.dll) and of scripts (plugins\script\bps and plugins\script\bps\gui). This article only handles plain script plugins. If you plan to use C++ for your extension please read about it in the Qt documentation.

Custom Script Extensions

When creating your own extensions, take care of the following naming conventions:

  • Name your plugin so that it does not conflict with standard bps plugins. For example if your company is ACME Corp, use plugins such as acme, acme.interface etc.
  • Plugin names must match the constraints of JavaScript variables. Do not use any blanks or special characters not allowed in a variable name, and start all parts of the plugin path names with a character allowed as first character of a JavaScript variable name.

Create your first plugin by creating a folder under the BPS plugins/script directory, and then create the extension script with the standard name __init__.js:

C:\Program Files\IBK BPS 2.19.0\plugins\script\test1\__init__.js:

__setupPackage__(__extension__);   // initialize extension
 
var ext = eval(__extension__);     // create shortcut for this extension
 
ext.version = '0.0.1';             // create a variable
 
ext.hello = function(aName)        // create a function
{
    print('Hello '+aName);
}

Now lets explain this:

__extension__
A predefined variable with the extension name. In this example the variable holds “custom”, in a sub-extension it may be “custom.interface” for example. Using this variable instead of the name directly is helpful if you ever need to rename, move or clone your extension, because the following script content is then independent of the actual extension name.


__setupPackage__ (__extension__);
A convenience function for setting up a “namespace” in the script environment. A typical application is to call __setupPackage__() with __extension__ as argument; e.g. __setupPackage__(“custom.interface.import”) would ensure that the object chain represented by the expression custom.interface.import exists in the script environment.


var ext = eval (__extension__);
The variable is a shortcut to the object (or namespace) “custom” that was created by the previous __setupPackage__ call. Instead of this shortcut you could as well access the namespace explicitely, but then you loose the code independance of the script name of cause.


The rest are examples how to create a variable and a function within the extension.

Next create a script to test the extension:

D:\myscripts\testext1.js:

importExtension('test1');         // load my extension
print(test1.version);             // use variable in my extension
test1.hello('Peter');             // use function in my extension

Run the script:

D:\myscripts>bps testext1
0.0.1
Hello Peter

D:\myscripts>

Dependent Extensions

As explained before it is possible to order extensions hierarchically, and the higher up (parent) extensions are assumed to be required for the sub-extensions. Qt Script will automatically load the parent extensions in advance when you load a sub-extension. For example

loadLibrary('a.b.c');

will let Qt Script first load extension a, then b and finally c. So by this one line you make all elements of the three extensions available to your script.

It is however important to have a minimal __init__.js in all extension directories even if no functions or variables are exposed by the extension. A minimal __init__.js should contain the line

__setupPackage__(__extension__);

Organizing Your Extensions

In the previous article we told that storing any custom scripts in the BPS installation directories is not recommended, and same is true of cause also for extensions.

Basically what we need to do is create an additional plugins directory and tell BPS to also look there for extensions.

Our directories shall be organized as this:

D:\myscripts Our main scripts are here
D:\myplugins\script\myexts Our root extension with general purpose functions
D:\myplugins\script\myexts\test2 Our special purpose extensions go all below D:\myscripts\script\myexts

Create the directory D:\myplugins\script

Create the directory D:\myplugins\script\myexts and create file __init__.js in it:

__setupPackage__(__extension__);
 
var ext = eval(__extension__);     // create shortcut for this extension
 
ext.version = __extension__ + ' 0.0.1';   // create a variable

Create directory D:\myplugins\script\myexts\test2 and create file __init__.js in it:

__setupPackage__(__extension__);   // initialize extension
 
var ext = eval(__extension__);     // create shortcut for this extension
 
ext.version = __extension__ + ' 0.0.2';   // create a variable
 
ext.hello = function(aName)        // create a function
{
    print('Hello '+aName);
}

Create the test application D:\myscripts\testext2.js:

importExtension('myexts.test2');  // load
print(myexts.version);            // use variable in my extension
print(myexts.test2.version);      // use variable in my sub-extension
myexts.test2.hello('John');       // use function in my sub-extension

If you run testext2 now it is not surprising that you get an error message, because BPS yet knows nothing about the custom plugins directory:

The trick is to declare a custom Plugins path in section [Paths] of the bps.conf file:

[Paths]
Plugins=D:/myplugins
Up to 2.19 a custom Plugins path needed to be set in a manually created qt.conf file. However starting with 2.20 qt.conf is created automatically during software installation and holds the default plugins path which can not be changed, otherwise the platform pluging introduced with Qt 5 will not get found.

Therefore from 2.20 you must set a custom Plugins path in bps.conf.

Forward slashes are used here in the path. When using backslashes in a .conf file path they would have to be doubled, for example
[Paths]
Plugins=D:\\myplugins
Instead of directory on a local disk you could also use a network share:
[Paths]
Plugins=//myserver/myshare/myplugins

However be aware that BPS execution will be blocked whenever the network share is unavailable. For best robustness it is recommended to put the custom plugin directory on a physical disk on the same machine where the BPS software is installed.

So now it should work:

Comments and Discussion

Enter your comment. Wiki syntax is allowed: