
org.codehaus.gant.GantBinding.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gant_groovy1.8 Show documentation
Show all versions of gant_groovy1.8 Show documentation
A framework for programming dependencies.
The newest version!
// Gant -- A Groovy way of scripting Ant tasks.
//
// Copyright © 2008--2011, 2013 Russel Winder
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing permissions and limitations under the
// License.
package org.codehaus.gant
import org.apache.tools.ant.BuildListener
import org.apache.tools.ant.Project
import org.apache.tools.ant.Target
/**
* This class is a sub-class of groovy.lang.Binding
to provide extra capabilities. In
* particular, all the extra bits needed in the binding for Gant to actually work at all. Handle this as a
* separate class to avoid replication of initialization if binding objects are cloned.
*
* @author Russel Winder
*/
public class GantBinding extends Binding implements Cloneable {
/**
* Determine whether we are initializing an instance and so are able to define the read-only items.
*/
private boolean initializing = true
/**
* A List of BuildListener instances that Gant sends events to.
*/
private List buildListeners = []
/**
* Default constructor.
*/
public GantBinding() {
setVariable('ant', new GantBuilder())
initializeGantBinding()
}
/**
* Constructor taking an explicit Binding
as parameter.
*
* @param binding The Binding
to use as a base of maplets to initialize the
* GantBinding
with.
*/
public GantBinding(final Binding binding) {
super(binding.variables)
setVariable('ant', new GantBuilder())
initializeGantBinding()
}
/**
* Constructor taking an explicit Project
as parameter.
*
* @param p The Project
to use when initializing the GantBuilder
.
*/
public GantBinding(final Project p) {
setVariable('ant', new GantBuilder(p))
initializeGantBinding()
}
/**
* Adds a BuildListener
instance to this Gant
instance
*/
public synchronized void addBuildListener(final BuildListener buildListener) {
if (buildListener) {
buildListeners << buildListener
ant.antProject.addBuildListener(buildListener)
}
}
/**
* Removes a BuildListener
instance from this Gant
instance
*/
public synchronized void removeBuildListener(final BuildListener buildListener) {
buildListeners.remove(buildListener)
ant.antProject.removeBuildListener(buildListener)
}
/**
* Call a target wrapped in BuildListener
event handler.
*/
private withTargetEvent(targetName, targetDescription, Closure callable) {
final antTarget = new Target(name : targetName, project : ant.antProject, description : targetDescription)
final event = new GantEvent(antTarget, this)
def targetResult = null
try {
buildListeners.each{BuildListener b -> b.targetStarted(event)}
targetResult = callable.call()
buildListeners.each{BuildListener b -> b.targetFinished(event)}
}
catch (Exception e) {
event.exception = e
buildListeners.each{BuildListener b -> b.targetFinished(event)}
throw e
}
return targetResult
}
/**
* Method holding all the code common to all construction.
*/
private void initializeGantBinding() {
// Do not allow the output of the ant.property call to escape. If the output is allowed out then Ant,
// Gant, Maven, Eclipse and IntelliJ IDEA all behave slightly differently. This makes testing nigh on
// impossible. Also the user doesn't need to know about these.
ant.logger.messageOutputLevel = GantState.SILENT
ant.property(environment : 'environment')
ant.logger.messageOutputLevel = GantState.verbosity
super.setVariable('includeTargets', new IncludeTargets(this))
super.setVariable('includeTool', new IncludeTool(this))
super.setVariable('globalPreHook', null)
super.setVariable('globalPostHook', null)
super.setVariable('terminateHook', {int returnValue, String elapseTime ->
owner.ant.project.log('\nBUILD ' +(returnValue == 0 ? 'SUCCESSFUL' : 'FAILED'))
owner.ant.project.log('Total time: ' + elapseTime)
})
super.setVariable('listOfTargetMapsDeclared', [ ])
super.setVariable('target', {Map map, Closure closure ->
def targetName = ''
def targetDescription = ''
def nameKey = 'name'
def descriptionKey = 'description'
Map targetMap = [:]
if (! map || map.size() == 0) { throw new RuntimeException('Target specified without a name.') }
// target(name : 'flob') is treated as a specification of target flob.
if (map.size() == 1 && ! map[nameKey]) {
// Implicit style of specifying a target and description.
targetName = map.keySet().iterator().next()
targetDescription = map[targetName]
// Create fake name/description entries in the map so that targets closures can still take
// advantage of it.name and it.description
targetMap[nameKey] = targetName
targetMap[descriptionKey] = targetDescription
}
else {
// Explicit style of specifying target name (and possibly description)
targetName = map[nameKey]
targetDescription = map[descriptionKey]
targetMap.putAll(map)
}
if (! targetName) { throw new RuntimeException('Target specified without a name.') }
try {
owner.getVariable((String)targetName)
//
// Exceptions thrown in this Closure appear not to cause execution to enter an error path. Must
// find out how to throw an exception from a Closure.
//
//throw new RuntimeException("Attempt to redefine " + targetName)
//
owner.binding.ant.project.log('Warning, target causing name overwriting of name ' + targetName, Project.MSG_WARN)
//System.exit(-101)
}
catch (MissingPropertyException mpe) { /* Intentionally empty */ }
if (targetDescription) { targetDescriptions.put(targetName, targetDescription) }
closure.metaClass = new GantMetaClass(closure.metaClass, owner)
if (! targetMap.containsKey('prehook')) { targetMap.prehook = [{-> owner.ant.project.log(targetName + ':')}] }
if (! targetMap.containsKey('posthook')) { targetMap.posthook = [{-> owner.ant.project.log('------ ' + targetName)}] }
if (targetMap.containsKey('addprehook')) {
if (targetMap.prehook instanceof Closure) { targetMap.prehook = [targetMap.prehook] }
if (targetMap.addprehook instanceof List) { targetMap.prehook += targetMap.addprehook }
else { targetMap.prehook += [targetMap.addprehook] }
}
if (targetMap.containsKey('addposthook')) {
if (targetMap.posthook instanceof Closure) { targetMap.posthook = [targetMap.posthook] }
if (targetMap.addposthook instanceof List) { targetMap.posthook = targetMap.addposthook + targetMap.posthook }
else { targetMap.posthook = [targetMap.addposthook] + targetMap.posthook }
}
final targetClosure = {
def returnCode = 0
def runHooks = {hook, String label ->
if (hook) {
if (hook instanceof Closure) { hook.call() }
else if (hook instanceof List) {
for (item in hook) {
if (item instanceof Closure) { item.call() }
else { owner.ant.project.log(label + ' list item is not a closure.', Project.MSG_ERR) }
}
}
else { owner.ant.project.log(label + ' not a closure or list (of closures).', Project.MSG_ERR) }
}
}
runHooks(owner.globalPreHook, 'Global prehook')
runHooks(targetMap.prehook, 'Target prehook')
withTargetEvent(targetName, targetDescription) { returnCode = closure(targetMap) }
runHooks(targetMap.posthook, 'Target posthook')
runHooks(owner.globalPostHook, 'Global posthook')
returnCode
}
owner.setVariable((String) targetName, targetClosure)
owner.setVariable(targetName + '_description', targetDescription) // For backward compatibility.
owner.getVariable('listOfTargetMapsDeclared') << targetMap
})
super.setVariable('setAllPerTargetPreHooks', { item ->
for (tgt in listOfTargetMapsDeclared) { tgt.prehook = item }
})
super.setVariable('setAllPerTargetPostHooks', { item ->
for (tgt in listOfTargetMapsDeclared) { tgt.posthook = item }
})
super.setVariable('addAllPerTargetPreHooks', { item ->
for (tgt in listOfTargetMapsDeclared) { tgt.prehook << item }
})
super.setVariable('addAllPerTargetPostHooks', { item ->
for (tgt in listOfTargetMapsDeclared) { tgt.posthook << item }
})
super.setVariable('task', {Map map, Closure closure ->
owner.ant.project.log('task has now been removed from Gant, please update your Gant files to use target instead of task.', Project.MSG_ERR)
System.exit(-99) ;
})
super.setVariable('targetDescriptions', new TreeMap())
super.setVariable('message', {String tag, Object message ->
def padding = 9 - tag.length()
if (padding < 0) { padding = 0 }
owner.ant.project.log(" ".substring(0, padding) + '[' + tag + '] ' + message)
})
super.setVariable('setDefaultTarget', {defaultTarget -> // Deal with Closure or String arguments.
switch (defaultTarget.class) {
case Closure :
String defaultTargetName = null
owner.variables.each{key, value -> if (value.is(defaultTarget)) { defaultTargetName = key }}
if (defaultTargetName == null) { throw new RuntimeException('Parameter to setDefaultTarget method is not a known target.') }
else { owner.forcedSettingOfVariable('defaultTarget', defaultTargetName) }
break
case String :
owner.forcedSettingOfVariable('defaultTarget', defaultTarget)
break
default :
throw new RuntimeException('Parameter to setDefaultTarget is of the wrong type -- must be a target reference or a string.')
}
})
super.setVariable('defaultTarget', 'default')
super.setVariable('setFinalizeTarget', {finalizeTarget -> // Deal with Closure or String arguments.
switch (finalizeTarget.class) {
case Closure :
String finalizeTargetName = null
owner.variables.each{key, value -> if (value.is(finalizeTarget)) { finalizeTargetName = key }}
if (finalizeTargetName == null) { throw new RuntimeException('Parameter to setFinalizeTarget method is not a known target.') }
else { owner.forcedSettingOfVariable('finalizeTarget', finalizeTargetName) }
break
case String :
owner.forcedSettingOfVariable('finalizeTarget', finalizeTarget)
break
default :
throw new RuntimeException('Parameter to setFinalizeTarget is of the wrong type -- must be a target reference or a string.')
}
})
super.setVariable('finalizeTarget', 'finalize')
super.setVariable('cacheEnabled', false)
final item = System.getenv().GANTLIB ;
if (item == null) { gantLib = [] }
else { gantLib = Arrays.asList(item.split(System.properties.'path.separator')) }
initializing = false
}
/**
* The method for getting values from the binding. Ensures that Ant properties appear to be in the binding object.
*/
Object getVariable(final String name) {
def returnValue
try { returnValue = super.getVariable(name) }
catch (final MissingPropertyException mpe) {
returnValue = super.getVariable('ant')?.project?.getProperty(name)
if (returnValue == null) { throw mpe }
}
returnValue
}
/**
* The method for setting values in the binding. Ensures that read-only values cannot be reset after
* initialization.
*
* @param name The symbol to define.
* @param value The value to associate with the name.
*/
void setVariable(final String name, final Object value) {
if (! initializing && [
'target',
'message',
'ant',
'includeTargets',
'includeTool',
'targetDescriptions',
'setDefaultTarget',
'initiatingTarget',
'targets',
'defaultTarget',
'finalizeTarget',
'listOfTargetMapsDeclared',
'setAllPerTargetPreHooks',
'setAllPerTargetPostHooks',
'addAllPerTargetPreHooks',
'addAllPerTargetPostHooks'
].contains(name)) { throw new RuntimeException('Cannot redefine symbol ' + name) }
super.setVariable(name, value)
}
/**
* setVariable
includes tests for certain names so as to make them read only as far as the
* Gant script is concerned. However the implementation code needs to be able to circumvent that
* checking, and so we provide this method for implementation code to force things at times other than
* initialization. This need came about in realizing GANT-44.
*
* @param ant the GantBuilder
to assign to the 'ant' entry in the binding.
*/
void forcedSettingOfVariable(final String name, final Object value) { super.setVariable(name, value) }
/**
* Getter for the list of build listeners. Used in {@code gant.Gant.withBuildListeners}.
*/
List getBuildListeners() { buildListeners }
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy