Generating Configuration Files
From ControlTier
This page describes strategies for generating configuration files for a Deployment resource.
Contents |
Configuration Life-cycle
An aspect of the deployment life cycle is generating configuration. Often this resolves down to producing customized configuration files based on an input of environment information.
Software configuration is supported by a standard set of Deployment commands:
- Configure: Runs the configuration cycle for the deployment. Configure
- Docs-Generate: Generate the configured template-based documents. (called by Configure) Docs-Generate
- Docs-Verify: Verify the documents generated by Docs-Generate. Docs-Verify
The Configure command is called by the Deploy workflow and follows after the Packages-Install command.
Generation Strategies
The following sections describe various strategies for generating configuration files.
Registered Document Transforms
Transforms can process and format your Model data so that it may be reused for generating configuration files.
Transforms have two parts.
- Transform definition. Transform definitions define the resource data to be used as input by the Transform, what template should be used, and where the output should be stored.
- Transform Template. Transform Templates provide the instructions for how the specified data should be processed and in what format it should be outputted. Templates are user provided and can either be
- plain text files that use a basic substitution scheme (replace hardcoded with Ant style property references)
- or, XSLT templates can be used. XSLT Templates give you the flexibility of standard XSL and provide for such programmatic techniques as conditionals and loops.
The default implementation of Docs-Generate processes the registered transforms, producing the desired output to the specified destination paths.
Registering a new Document
There are two methods to register new transforms: via Graphical resource editor or scripted via a command.
Register via GUI
Defining a Transform in the Graphical resource editor begins by navigating to the resource for which you want to associate the document.
In the "Details" view scroll down and locate the "Documents" link and click it. That will reveal a "+ add document" button.
Figure: Add Document button
This will bring you to the first form. In this form you specify the "degree(s) away" and which dependencies to include. Typically, you just accept these defaults. Then push the "Continue..." button where you will finalize the registration.
Figure: Step 1 of creating new Transform. This step creates the View definition
During this last step you will specify the destination path information for the generated results, the type of template, and the template location. You'll notice the little magnifying glass icon next to the "Template" text field. Pressing that icon will bring you to a WebDAV browser that lets you choose a template that resides on the WebDAV. Alternatively, you can specify a path that will be local to the deployed resource. The paths can reference properties that are accessible to the resource.
Figure: Step 2 of creating new Transform. This step defines the Document and Template parameters
After completing the form you will be forwarded to a page summarizing the document definition. Click the "← Back to Object View" page to return to the resource's detail page. Once returned, you will notice that the "Documents" link will now list the newly defined document.
Register via a command
It may not be desirable or feasible to register the document transforms via the Graphical resource editor. This section describes an alternative that lets you script the document registrations via Ant tasks, in a separate command that can reside in one of your custom types.
Below is an example definition for a JBossServer [1] command called "Docs-Register" that takes a list of file names and registers them as Document transforms. The specified templates are all local to the module itself.
Once defined, this "Docs-Register" command could be invoked as the first step of the Configure workflow or perhaps in another workflow (e.g., "Prepare").
<command name="Docs-Register" description="Example: registers configuration documents required for jboss operation"
command-type="AntCommand">
<implementation>
<!-- Register the documents generated from these templates: templates/jboss-4.0.3SP1/server/default: -->
<for list="bindings.xml,jboss-service.xml,run.conf" param="file">
<sequential>
<transform-create depot="${context.depot}"
resultproperty="transform-create.result"
comment="the JBoss @{file} configuration">
<context direction="internal" proximity="1"
maprefUri="${entity.mapref-uri}" />
<document type="text-plain"
file="@{file}"
dir="${opts.basedir}/conf" />
<template type="simple"
file="@{file}.template"
dir="${module.dir}/templates/jboss-${opts.jboss_version}/server/default/conf" />
</transform-create>
<echo level="info">Registered document: @{file}.</echo>
</sequential>
</for>
</implementation>
<opts>
<opt parameter="basedir" description="base directory of the jboss instance"
required="false" property="opts.basedir" type="string"
defaultproperty="entity.attribute.jboss_basedir"/>
<opt parameter="install_root" description=""
required="false" property="opts.install_root" type="string"
defaultproperty="entity.attribute.jboss_install_root" />
<opt parameter="jboss_version" description="version of the jboss server package"
required="false" type="string"
defaultproperty="entity.attribute.jboss_version" property="opts.jboss_version" />
</opts>
</command>
This example command is based on an Ant task called transform-create that registers document transforms just like one can do via the Graphical resource editor. The transform-create task is called inside the body of an Ant-contrib for loop. You will notice nested elements that together describe the Transform Document
- context: The
contextelement defines the property data scope for this resource (entity.mapref-uri) showing just child dependency info (proximity=1, direction=internal) - document: The
documentelement specifies the file type (text-plain) and the output path information (file and dir) - template: The
templateelement specifies the kind of template (simple) and the path to the template (file and dir)
After the "Docs-Register" command completes, three documents will be defined and associated with this resource.
Transform Ant Tasks
There are a number of Ant tasks that are available for managing the registration and processing of Transforms and templates:
- Transform Task Reference
- TransformCreate Task Reference
- TransformGet Task Reference
- TemplateCreate Task Reference
Overridden Configure Workflow
The default "Docs-Generate" command is sufficient for many use cases. Where completely custom logic is needed, it is best to override the Configure workflow, usually overriding the "Docs-Generate" command directly.
The kind of custom logic required will be based on your particular use case but often there are two reasons:
- The data needed as input to a template must be programatically obtained. The data may be derived from object properties or obtained from an external source.
- The file being generated is not from a simple token substitution template but is programatically written.
The following sections provide tips for how you might go about implementing either kind of logic. Be aware that these are only suggestions that illustrate rough strategies as your needs will be very specific.
Override Docs-Generate
The first step is to override the Docs-Generate to replace its implementation with your own. The general instructions for overriding an inherited command are found here: Override an inherited command.
You might also create an entirely separate command (naming it whatever you want) and override the Configure workflow to include it.
The examples below override Docs-Generate. Keep in mind it is important to preserve existing options when overriding an inherited command.
Be sure that you define these options when overriding Docs-Generate:
Docs-Generate [-archivedir <${entity.instance.dir}/var>] [-buildstamp <>]
Programmatic data access
This section describes scenarios where the data required is not only from the object's properties. The examples use Ant command implementations but you can implement Docs-Generate using the approach you prefer (e.g, shell, BSF). Ant command implementations are useful because tasks exist for simple filter-based token substitution.
Derived data
Derived data is any kind that is computed from the data in the object's context. For example, you might need to calculate a number representing a counter index, a date or time, or a string of concatenated values.
Below is an example "Docs-Generate" that defines two values and passes them in as named tokens via the Ant copy task.
<command name="Docs-Generate" description="Docs-Generate example showing derived data."
command-type="AntCommand" >
<implementation>
<!--
make a calculation
-->
<math result="buildstampPlus3" operand1="3" operation="+" operand2="${opts.buildstamp}" datatype="int"/>
<!--
generate a date/time stamp
-->
<tstamp>
<format property="dstamp" pattern="d-MMMM-yyyy" locale="en,UK"/>
</tstamp>
<!--
Copy a set of files to a directory, replacing @BUILD_OFFSET@ and @TODAY@ in all files.
-->
<copy todir="${entity.instance.dir}/var">
<fileset dir="${module.dir}/templates"/>
<filterset filtersfile="${entity.properties.file}">
<filter token="BUILD_OFFSET" value="${buildstampPlus3}"/>
<filter token="TODAY" value="${dstamp}"/>
</filterset>
</copy>
</implementation>
<opts>
<opt parameter="archivedir" description="dir to preserve current output docs"
required="false" property="opts.archivedir" type="string"
default="${entity.instance.dir}/var/archived"/>
<opt parameter="buildstamp" description="build identifer. currently ignored"
required="false" property="opts.buildstamp" type="string"
default="0"/>
</opts>
</command>
The first value, buildstampPlus3, defines a hypothetical offset referenced as "BUILD_OFFSET" in the template files.
The second value, dstamp, defines a datestamp referenced as "TODAY".
Also note, that the object's properties are also included via the filtersfile attribute. This allows you to use any of those property key names as tokens inside the template files, too.
Data from other objects
The data needed as input to your generated document may exist in another object. This object may be associated by parent or child relationship or may be arbitrarily specified.
The simplest method to get data about another object is via the get-properties Ant task.
The example below obtains the properties for the Node object registered for the local CTL instance:
<command name="Docs-Generate" description="Docs-Generate example showing data retrieved from another object."
command-type="AntCommand" >
<implementation>
<!--
Get the properties for the local CTL Node
-->
<get-properties serverUrl="${framework.server.url}"
depot="${context.depot}"
resultproperty="rs"
comment="none"
destdir="${entity.instance.dir}/var"
destfile="node-info.properties"
>
<context direction="internal" proximity="1"
entityName="${framework.node.name}" entityClass="${framework.node.type}"/>
</get-properties>
<!--
Read the node property file prefixing each property name with the "node."
-->
<property file="${entity.instance.dir}/var/node-info.properties" prefix="node"/>
<!-- You can use the echoproperties task to print all the obtained properties:
<echoproperties prefix="node"/>
eg,
node.entity.hostname=strongbad
node.entity.os-arch=i386
node.entity.os-family=unix
node.entity.os-name=Mac OS X
node.entity.os-version=10.5.6
-->
<!--
Copy a set of files to a directory, replacing @HOSTNAME@, @ARCH@, @OSFAMILY@, @OSNAME@ and @OSVERSION@ in all files.
-->
<copy todir="${entity.instance.dir}/var">
<fileset dir="${module.dir}/templates"/>
<filterset>
<filter token="HOSTNAME" value="${node.entity.hostname}"/>
<filter token="ARCH" value="${node.entity.os-arch}"/>
<filter token="OSFAMILY" value="${node.entity.os-family}"/>
<filter token="OSNAME" value="${node.entity.os-name}"/>
<filter token="OSVERSION" value="${node.entity.os-version}"/>
</filterset>
</copy>
</implementation>
<opts>
<opt parameter="archivedir" description="dir to preserve current output docs"
required="false" property="opts.archivedir" type="string"
default="${entity.instance.dir}/var/archived"/>
<opt parameter="buildstamp" description="build identifer. currently ignored"
required="false" property="opts.buildstamp" type="string"
default="0"/>
</opts>
</command>
This example defines several tokens (HOSTNAME, ARCH, OSFAMILY, OSNAME, OSVERSION) each associated with a value from the Node's properties.
Data from an external source
The generated documents may require data input from an external tool. In this case, the goal is to make the external call and save the output into a format that is convenient for your template and template processor.
The example below calls out to the Subversion client via shell command and saves the output into XML. The Ant task, xmlproperty, is used to read the XML content and generate Ant properties. Once in property form, several named tokens are defined for processing by the Ant copy task and filterset type.
<command name="Docs-Generate" description="Docs-Generate example showing data retrieved from external source."
command-type="AntCommand">
<implementation>
<!--
Get the data from an external source: Subversion change revision info
-->
<var name="vinfo.output" unset="true"/>
<tempfile property="vinfo.output" destdir="${entity.instance.dir}/var" suffix=".out"/>
<echo>Checking "${opts.connection}" for the last changed revision ...</echo>
<exec executable="svn" output="${vinfo.output}">
<arg line="info --xml --non-interactive ${opts.connection}"/>
</exec>
<!--
Read the generated xml file prefixing each property name with the "svn."
-->
<xmlproperty file="${vinfo.output}" prefix="svn" collapseAttributes="true"/>
<!-- You can use the echoproperties task to print all the obtained properties:
<echoproperties prefix="svn"/>
eg,
#Ant properties
#Wed Mar 25 11:10:30 PDT 2009
svn.info.entry.commit.author=gschueler
svn.info.entry.commit.date=2009-03-24T19\:35\:00.124507Z
svn.info.entry.commit.revision=9107
svn.info.entry.kind=dir
svn.info.entry.path=branches
svn.info.entry.repository.root=http\://controltier.svn.sourceforge.net/svnroot/controltier
svn.info.entry.repository.uuid=07ebc575-2234-0410-9739-bcfe40894a14
svn.info.entry.revision=9107
svn.info.entry.url=http\://controltier.svn.sourceforge.net/svnroot/controltier/branches
-->
<!--
Copy a set of files to a directory, replacing @AUTHOR@, @REVISION@, @DATE@ in all files.
-->
<copy todir="${entity.instance.dir}/var">
<fileset dir="${module.dir}/templates"/>
<filterset>
<filter token="AUTHOR" value="${svn.info.entry.commit.author}"/>
<filter token="REVISION" value="${svn.info.entry.revision}"/>
<filter token="DATE" value="${svn.info.entry.commit.date}"/>
</filterset>
</copy>
</implementation>
<opts>
<opt parameter="connection" description="The SCM connection string"
required="true" property="opts.connection" type="string"/>
<opt parameter="archivedir" description="dir to preserve current output docs"
required="false" property="opts.archivedir" type="string"
default="${entity.instance.dir}/var/archived"/>
<opt parameter="buildstamp" description="build identifer. currently ignored"
required="false" property="opts.buildstamp" type="string"
default="0"/>
</opts>
</command>
Program generated output
There are cases when simple token substitution template files are insufficient to generate the needed configuration files. This is a difference between content and structure:
- content differences are a matter of different values used in the same places in a template
- structure differences are a matter of the file size and arrangement being different
There are basically two approaches used for these cases: XSLT transforms and ad-hoc.
XSLT Transforms
XSLT transforms are based on an XML input and an XSL style sheet used as a template. XSLT transform documents are supported by the ControlTier server allowing you to maintain the style sheet on the server and have the server generate it for you. The results are saved locally.
The example below calls the transform task to have the server process an XSL template using the specified object's model as input. Internally, the server provides the model data as XML and then executes the transformation using the specified template.
<command name="Docs-Generate" description="Docs-Generate example showing server side XSLT transform."
command-type="AntCommand" >
<implementation>
<transform depot="${context.depot}"
resultproperty="transform.result"
comment="the JBoss @{file} configuration"
destdir="${entity.instance.dir}"
destfile="document.out"
>
<context direction="internal" proximity="1"
maprefUri="${entity.mapref-uri}" />
<template type="xsl"
file="ctl-entity-properties.xsl"
dir="/templates" />
</transform>
</implementation>
<opts>
<opt parameter="archivedir" description="dir to preserve current output docs"
required="false" property="opts.archivedir" type="string"
default="${entity.instance.dir}/var/archived"/>
<opt parameter="buildstamp" description="build identifer. currently ignored"
required="false" property="opts.buildstamp" type="string"
default="0"/>
</opts>
</command>
Alternatively, you can use an XSLT processor that is local to the client (such as the Ant XSLT task).
Ad-hoc Generation
Ad-hoc generation of configuration files basically means, anything goes. The use case here is the file that will be generated must be done via a program. Your requirements dictate the logic of the program but may include
- conditionals based on environment
- iterating over a set of values
- including or excluding stanzas of content
- may utilize one or more template file fragments
The following example implements "Docs-Generate" as a BSF_command type using the Groovy scripting language. The example produces a hypothetical configuration file called "foo.ini" using a simple key/value pair format.
<command name="Docs-Generate" description="Docs-Generate example showing ad-hoc generation."
command-type="BsfCommand">
<script language="groovy"><![CDATA[
// define some data. this data could be from any source mentioned in earlier sections
def fields = ["a":"1", "b":"2", "c":"3"]
// open the destination file for write action
new File(project.properties['entity.instance.dir'], "foo.ini").withWriter { out ->
// add a comment
out.writeLine("# Do not edit! This file was program generated.")
// add the boilerplate config stuff
out.writeLine("foo=bar")
out.writeLine("bar=baz")
// now iterate through the data set
fields.each() { key, value ->
// implement some conditional logic
if (true) {
// write a new line to the destination file:
out.writeLine("${key}=${value}")
}
}
}
println "wrote: ${project.properties['entity.instance.dir']}/foo.ini"
]]></script>
<opts>
<opt parameter="archivedir" description="dir to preserve current output docs"
required="false" property="opts.archivedir" type="string"
default="${entity.instance.dir}/var/archived"/>
<opt parameter="buildstamp" description="build identifer. currently ignored"
required="false" property="opts.buildstamp" type="string"
default="0"/>
</opts>
</command>
The result of this Docs-Generate is a file with the following content:
# Do not edit! This file was program generated. foo=bar bar=baz a=1 b=2 c=3
Running Docs-Generate
The usage for Docs-Generate is as follows: ctl -p project -t type -o object -c Docs-Generate
Appendix
Example type.xml
Here is a complete file listing of a type.xml containing the examples mentioned in this page.
You can build this type by first creating the module source tree via ProjectBuilder's create-type command:
ctl -p demo -m ProjectBuilder -c create-type -- -type ConfigGeneration -supertype Deployment
Then replace the generated type.xml from create-type with the content shown below.
<?xml version="1.0" encoding="UTF-8"?>
<!--
This document is used to define one or more Types.
For reference, see: http://apps.sourceforge.net/mediawiki/controltier/index.php?title=Type-v10.xml
-->
<types
xmlns:module="http://open.controltier.com/base/Modules#"
xmlns:type="http://open.controltier.com/base/Types#"
xmlns:cmd="http://open.controltier.com/base/Modules/Commands#">
<!-- The type element defines a Type and command module. -->
<type
name="ConfigGeneration"
role="concrete"
uniqueInstances="true">
<!-- description of the Type -->
<description>examples for config file generation</description>
<supertype>
<!-- supertype/typereference: defines the supertype of the Type -->
<typereference name="Deployment"/>
</supertype>
<command-settings>
<!-- command-settings: properties of the command module -->
<!-- See Wiki: -->
<!-- http://apps.sourceforge.net/mediawiki/controltier/index.php?title=Type-v10.xml#command-settings -->
<notification notify="false"/>
<template-directory></template-directory>
<dependency-view parents="false" children="true" proximity="1"/>
<logger name="ConfigGeneration"/>
</command-settings>
<attributes>
<!-- Define attributes of the Type here -->
<!-- See Wiki: -->
<!-- http://apps.sourceforge.net/mediawiki/controltier/index.php?title=Type-v10.xml#attributes -->
</attributes>
<constraints>
<!-- Define constraints of the Type here -->
<!-- See Wiki: -->
<!-- http://apps.sourceforge.net/mediawiki/controltier/index.php?title=Type-v10.xml#constraints -->
</constraints>
<commands>
<!-- Define commands here -->
<!-- See the Documentation on the ControlTier Wiki: -->
<!-- http://apps.sourceforge.net/mediawiki/controltier/index.php?title=Type-v10.xml#commands -->
<command name="Docs-Generate-1" description="Docs-Generate example showing derived data."
command-type="AntCommand" >
<implementation>
<!--
make a calculation
-->
<math result="buildstampPlus3" operand1="3" operation="+" operand2="${opts.buildstamp}" datatype="int"/>
<!--
generate a datetime stamp
-->
<tstamp>
<format property="TODAY_UK" pattern="d-MMMM-yyyy" locale="en,UK"/>
</tstamp>
<!--
Copy a set of files to a directory, replacing @BUILD_OFFSET@ and @TODAY@ in all files.
-->
<copy todir="${entity.instance.dir}/var">
<fileset dir="${module.dir}/templates"/>
<filterset filtersfile="${entity.properties.file}">
<filter token="BUILD_OFFSET" value="${buildstampPlus3}"/>
<filter token="TODAY" value="${TODAY_UK}"/>
</filterset>
</copy>
</implementation>
<opts>
<opt parameter="archivedir" description="dir to preserve current output docs"
required="false" property="opts.archivedir" type="string"
default="${entity.instance.dir}/var/archived"/>
<opt parameter="buildstamp" description="build identifer. currently ignored"
required="false" property="opts.buildstamp" type="string"
default="0"/>
</opts>
</command>
<command name="Docs-Generate-2" description="Docs-Generate example showing data retrieved from another object."
command-type="AntCommand" >
<implementation>
<!--
Get the properties for the local CTL Node
-->
<get-properties serverUrl="${framework.server.url}"
depot="${context.depot}"
resultproperty="rs"
comment="none"
destdir="${entity.instance.dir}/var"
destfile="node-info.properties"
>
<context direction="internal" proximity="1"
entityName="${framework.node.name}" entityClass="${framework.node.type}"/>
</get-properties>
<!--
Read the node property file prefixing each property name with the "node."
-->
<property file="${entity.instance.dir}/var/node-info.properties" prefix="node"/>
<!-- You can use the echoproperties task to print all the obtained properties:
<echoproperties prefix="node"/>
eg,
node.entity.hostname=strongbad
node.entity.os-arch=i386
node.entity.os-family=unix
node.entity.os-name=Mac OS X
node.entity.os-version=10.5.6
-->
<!--
Copy a set of files to a directory, replacing @BUILD_OFFSET@ and @TODAY@ in all files.
-->
<copy todir="${entity.instance.dir}/var">
<fileset dir="${module.dir}/templates"/>
<filterset>
<filter token="HOSTNAME" value="${node.entity.hostname}"/>
<filter token="ARCH" value="${node.entity.os-arch}"/>
<filter token="OSFAMILY" value="${node.entity.os-family}"/>
<filter token="OSNAME" value="${node.entity.os-name}"/>
<filter token="OSVERSION" value="${node.entity.os-version}"/>
</filterset>
</copy>
</implementation>
<opts>
<opt parameter="archivedir" description="dir to preserve current output docs"
required="false" property="opts.archivedir" type="string"
default="${entity.instance.dir}/var/archived"/>
<opt parameter="buildstamp" description="build identifer. currently ignored"
required="false" property="opts.buildstamp" type="string"
default="0"/>
</opts>
</command>
<command name="Docs-Generate-3" description="Docs-Generate example showing data retrieved from external source."
command-type="AntCommand" >
<implementation>
<!--
Get the data from an external source: Subversion change revision info
-->
<var name="vinfo.output" unset="true"/>
<tempfile property="vinfo.output" destdir="${entity.instance.dir}/var" suffix=".out"/>
<echo>Checking "${opts.connection}" for the last changed revision ...</echo>
<exec executable="svn" output="${vinfo.output}">
<arg line="info --xml --non-interactive ${opts.connection}"/>
</exec>
<!--
Read the generated xml file prefixing each property name with the "svn."
-->
<xmlproperty file="${vinfo.output}" prefix="svn" collapseAttributes="true"/>
<!-- You can use the echoproperties task to print all the obtained properties:
<echoproperties prefix="svn"/>
eg,
#Ant properties
#Wed Mar 25 11:10:30 PDT 2009
svn.info.entry.commit.author=gschueler
svn.info.entry.commit.date=2009-03-24T19\:35\:00.124507Z
svn.info.entry.commit.revision=9107
svn.info.entry.kind=dir
svn.info.entry.path=branches
svn.info.entry.repository.root=http\://controltier.svn.sourceforge.net/svnroot/controltier
svn.info.entry.repository.uuid=07ebc575-2234-0410-9739-bcfe40894a14
svn.info.entry.revision=9107
svn.info.entry.url=http\://controltier.svn.sourceforge.net/svnroot/controltier/branches
-->
<!--
Copy a set of files to a directory, replacing @AUTHOR@, @REVISION@, @DATE@ in all files.
-->
<copy todir="${entity.instance.dir}/var">
<fileset dir="${module.dir}/templates"/>
<filterset>
<filter token="AUTHOR" value="${svn.info.entry.commit.author}"/>
<filter token="REVISION" value="${svn.info.entry.revision}"/>
<filter token="DATE" value="${svn.info.entry.commit.date}"/>
</filterset>
</copy>
</implementation>
<opts>
<opt parameter="connection" description="The SCM connection string"
required="true" property="opts.connection" type="string"/>
<opt parameter="archivedir" description="dir to preserve current output docs"
required="false" property="opts.archivedir" type="string"
default="${entity.instance.dir}/var/archived"/>
<opt parameter="buildstamp" description="build identifer. currently ignored"
required="false" property="opts.buildstamp" type="string"
default="0"/>
</opts>
</command>
<command name="Docs-Generate-4" description="Docs-Generate example showing server side XSLT transform."
command-type="AntCommand" >
<implementation>
<transform depot="${context.depot}"
resultproperty="transform.result"
comment="the JBoss @{file} configuration"
destdir="${entity.instance.dir}"
destfile="document.out"
>
<context direction="internal" proximity="1"
maprefUri="${entity.mapref-uri}" />
<template type="xsl"
file="ctl-entity-properties.xsl"
dir="/templates" />
</transform>
</implementation>
<opts>
<opt parameter="archivedir" description="dir to preserve current output docs"
required="false" property="opts.archivedir" type="string"
default="${entity.instance.dir}/var/archived"/>
<opt parameter="buildstamp" description="build identifer. currently ignored"
required="false" property="opts.buildstamp" type="string"
default="0"/>
</opts>
</command>
<command name="Docs-Generate-5" description="Docs-Generate example showing ad-hoc generation."
command-type="BsfCommand" >
<script language="groovy"><![CDATA[
// define some data. this data could be from any source mentioned in earlier sections
def fields = ["a":"1", "b":"2", "c":"3"]
// open the destination file for write action
new File(project.properties['entity.instance.dir'], "foo.ini").withWriter { out ->
// add a comment
out.writeLine("# Do not edit! This file was program generated.")
// add the boilerplate config stuff
out.writeLine("foo=bar")
out.writeLine("bar=baz")
// now iterate through the data set
fields.each() { key, value ->
// implement some conditional logic
if (true) {
// write a new line to the destination file:
out.writeLine("${key}=${value}")
}
}
}
println "wrote: ${project.properties['entity.instance.dir']}/foo.ini "
]]></script>
<opts>
<opt parameter="archivedir" description="dir to preserve current output docs"
required="false" property="opts.archivedir" type="string"
default="${entity.instance.dir}/var/archived"/>
<opt parameter="buildstamp" description="build identifer. currently ignored"
required="false" property="opts.buildstamp" type="string"
default="0"/>
</opts>
</command>
</commands>
</type>
<!--
Multiple <type> elements are allowed.
-->
</types>
| |||||||||||||||||||||||




