git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@676095 13f79535-47bb-0310-9956-ffa450edef68master
@@ -153,6 +153,8 @@ Other changes: | |||
a build if a warning occurs. | |||
Bugzilla Report 41836. | |||
* Ant now supports local properties. Bugzilla report 23942. | |||
Changes from Ant 1.7.0 TO Ant 1.7.1 | |||
============================================= | |||
@@ -0,0 +1,53 @@ | |||
<!-- | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You 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. | |||
--> | |||
<html> | |||
<head> | |||
<meta http-equiv="Content-Language" content="en-us"> | |||
<link rel="stylesheet" type="text/css" href="../stylesheets/style.css"> | |||
<title>Local Task</title> | |||
</head> | |||
<body> | |||
<h2>Local</h2> | |||
<h3>Description</h3> | |||
<p>Adds a local property to the current scope. Property scopes exist at Ant's | |||
various "block" levels. These include targets as well as the | |||
<a href="parallel.html">Parallel</a> and <a href="sequential.html">Sequential</a> | |||
task containers (including <a href="macrodef.html">Macrodef</a> bodies). A local | |||
property at a given scope "shadows" properties of the same name at higher scopes, | |||
including the global scope (declaring a local property at the global level, i.e. | |||
outside of any scope block, has no effect). <b>Since Ant 1.8</b></p> | |||
<h3>Parameters</h3> | |||
<table border="1" cellpadding="2" cellspacing="0"> | |||
<tr> | |||
<td valign="top"><b>Attribute</b></td> | |||
<td valign="top"><b>Description</b></td> | |||
<td align="center" valign="top"><b>Required</b></td> | |||
</tr> | |||
<tr> | |||
<td valign="top">name</td> | |||
<td valign="top">The property to declare in the current scope</td> | |||
<td valign="top" align="center">Yes</td> | |||
</tr> | |||
</table> | |||
</body> | |||
</html> | |||
@@ -86,6 +86,7 @@ | |||
<a href="CoreTasks/loadfile.html">LoadFile</a><br/> | |||
<a href="CoreTasks/loadproperties.html">LoadProperties</a><br/> | |||
<a href="CoreTasks/loadresource.html">LoadResource</a><br/> | |||
<a href="CoreTasks/local.html">Local</a><br/> | |||
<a href="CoreTasks/makeurl.html">MakeURL</a><br/> | |||
<a href="CoreTasks/mail.html">Mail</a><br/> | |||
<a href="CoreTasks/macrodef.html">MacroDef</a><br/> | |||
@@ -174,6 +174,12 @@ public final class MagicNames { | |||
*/ | |||
public static final String REFID_PROPERTY_HELPER = "ant.PropertyHelper"; | |||
/** | |||
* Reference used to store the local properties. | |||
* Value: {@value} | |||
*/ | |||
public static final String REFID_LOCAL_PROPERTIES = "ant.LocalProperties"; | |||
/** | |||
* Name of JVM system property which provides the name of the ProjectHelper class to use. | |||
* Value: {@value} | |||
@@ -25,6 +25,8 @@ import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.StringTokenizer; | |||
import org.apache.tools.ant.property.LocalProperties; | |||
/** | |||
* Class to implement a target object with required parameters. | |||
* | |||
@@ -347,14 +349,22 @@ public class Target implements TaskContainer { | |||
*/ | |||
public void execute() throws BuildException { | |||
if (testIfCondition() && testUnlessCondition()) { | |||
for (int taskPosition = 0; taskPosition < children.size(); ++taskPosition) { | |||
Object o = children.get(taskPosition); | |||
if (o instanceof Task) { | |||
Task task = (Task) o; | |||
task.perform(); | |||
} else { | |||
((RuntimeConfigurable) o).maybeConfigure(project); | |||
LocalProperties localProperties | |||
= LocalProperties.get(getProject()); | |||
localProperties.enterScope(); | |||
try { | |||
for (int taskPosition = 0; taskPosition < children.size(); | |||
++taskPosition) { | |||
Object o = children.get(taskPosition); | |||
if (o instanceof Task) { | |||
Task task = (Task) o; | |||
task.perform(); | |||
} else { | |||
((RuntimeConfigurable) o).maybeConfigure(project); | |||
} | |||
} | |||
} finally { | |||
localProperties.exitScope(); | |||
} | |||
} else if (!testIfCondition()) { | |||
project.log(this, "Skipped because property '" + project.replaceProperties(ifCondition) | |||
@@ -0,0 +1,152 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You 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.apache.tools.ant.property; | |||
import org.apache.tools.ant.PropertyHelper; | |||
import org.apache.tools.ant.Project; | |||
import org.apache.tools.ant.MagicNames; | |||
/** | |||
* Thread local class containing local properties. | |||
* @since Ant 1.8.0 | |||
*/ | |||
public class LocalProperties | |||
extends InheritableThreadLocal | |||
implements PropertyHelper.PropertyEvaluator, | |||
PropertyHelper.PropertySetter { | |||
/** | |||
* Get a localproperties for the given project. | |||
* @param project the project to retieve the localproperties for. | |||
* @return the localproperties. | |||
*/ | |||
public static synchronized LocalProperties get(Project project) { | |||
LocalProperties l = (LocalProperties) project.getReference( | |||
MagicNames.REFID_LOCAL_PROPERTIES); | |||
if (l == null) { | |||
l = new LocalProperties(); | |||
project.addReference(MagicNames.REFID_LOCAL_PROPERTIES, l); | |||
PropertyHelper.getPropertyHelper(project).add(l); | |||
} | |||
return l; | |||
} | |||
// -------------------------------------------------- | |||
// | |||
// Thread stuff | |||
// | |||
// -------------------------------------------------- | |||
/** | |||
* Construct a new LocalProperties object. | |||
*/ | |||
private LocalProperties() { | |||
} | |||
/** | |||
* Get the initial value. | |||
* @return a new localproperties stack. | |||
*/ | |||
protected synchronized Object initialValue() { | |||
return new LocalPropertyStack(); | |||
} | |||
private LocalPropertyStack current() { | |||
return (LocalPropertyStack) get(); | |||
} | |||
// -------------------------------------------------- | |||
// | |||
// Local property adding and scoping | |||
// | |||
// -------------------------------------------------- | |||
/** | |||
* Add a local property to the current scope. | |||
* @param property the property name to add. | |||
*/ | |||
public void addLocal(String property) { | |||
current().addLocal(property); | |||
} | |||
/** enter the scope */ | |||
public void enterScope() { | |||
current().enterScope(); | |||
} | |||
/** exit the scope */ | |||
public void exitScope() { | |||
current().exitScope(); | |||
} | |||
// -------------------------------------------------- | |||
// | |||
// Copy - used in parallel to make a new stack | |||
// | |||
// -------------------------------------------------- | |||
/** | |||
* Copy the stack for a parallel thread. | |||
* To be called from the parallel thread itself. | |||
*/ | |||
public void copy() { | |||
set(current().copy()); | |||
} | |||
// -------------------------------------------------- | |||
// | |||
// PropertyHelper delegate methods | |||
// | |||
// -------------------------------------------------- | |||
/** | |||
* Evaluate a property. | |||
* @param property the property's String "identifier". | |||
* @param helper the invoking PropertyHelper. | |||
* @return Object value. | |||
*/ | |||
public Object evaluate(String property, PropertyHelper helper) { | |||
return current().evaluate(property, helper); | |||
} | |||
/** | |||
* Set a *new" property. | |||
* @param property the property's String "identifier". | |||
* @param value the value to set. | |||
* @param propertyHelper the invoking PropertyHelper. | |||
* @return true if this entity 'owns' the property. | |||
*/ | |||
public boolean setNew( | |||
String property, Object value, PropertyHelper propertyHelper) { | |||
return current().setNew(property, value, propertyHelper); | |||
} | |||
/** | |||
* Set a property. | |||
* @param property the property's String "identifier". | |||
* @param value the value to set. | |||
* @param propertyHelper the invoking PropertyHelper. | |||
* @return true if this entity 'owns' the property. | |||
*/ | |||
public boolean set( | |||
String property, Object value, PropertyHelper propertyHelper) { | |||
return current().set(property, value, propertyHelper); | |||
} | |||
} | |||
@@ -0,0 +1,151 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You 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.apache.tools.ant.property; | |||
import java.util.LinkedList; | |||
import java.util.HashMap; | |||
import java.util.Iterator; | |||
import java.util.Map; | |||
import org.apache.tools.ant.PropertyHelper; | |||
/** | |||
* A stack of local property maps. | |||
* There is a map for each scope (target, sequential, macro). | |||
* @since Ant 1.8.0 | |||
*/ | |||
public class LocalPropertyStack { | |||
private LinkedList stack = new LinkedList(); | |||
// -------------------------------------------------- | |||
// | |||
// Local property adding and scoping | |||
// | |||
// -------------------------------------------------- | |||
/** | |||
* Add a local property. | |||
* @param property the name of the local proeprty. | |||
*/ | |||
public void addLocal(String property) { | |||
if (!stack.isEmpty()) { | |||
((Map) stack.getFirst()).put(property, NullReturn.NULL); | |||
} | |||
} | |||
/** | |||
* Enter the local scope. | |||
*/ | |||
public void enterScope() { | |||
stack.addFirst(new HashMap()); | |||
} | |||
/** | |||
* Exit the local scope. | |||
*/ | |||
public void exitScope() { | |||
((HashMap) stack.removeFirst()).clear(); | |||
} | |||
// -------------------------------------------------- | |||
// | |||
// Copy - used in parallel to make a new stack | |||
// | |||
// -------------------------------------------------- | |||
/** | |||
* Copy the stack for a parallel thread. | |||
* @return a copy. | |||
*/ | |||
public LocalPropertyStack copy() { | |||
LocalPropertyStack ret = new LocalPropertyStack(); | |||
ret.stack.addAll(stack); | |||
return ret; | |||
} | |||
// -------------------------------------------------- | |||
// | |||
// PropertyHelper delegate methods | |||
// | |||
// -------------------------------------------------- | |||
/** | |||
* Evaluate a property. | |||
* @param property the property's String "identifier". | |||
* @param helper the invoking PropertyHelper. | |||
* @return Object value. | |||
*/ | |||
public Object evaluate(String property, PropertyHelper helper) { | |||
for (Iterator i = stack.iterator(); i.hasNext();) { | |||
Map map = (Map) i.next(); | |||
Object ret = map.get(property); | |||
if (ret != null) { | |||
return ret; | |||
} | |||
} | |||
return null; | |||
} | |||
/** | |||
* Set a *new" property. | |||
* @param property the property's String "identifier". | |||
* @param value the value to set. | |||
* @param propertyHelper the invoking PropertyHelper. | |||
* @return true if this entity 'owns' the property. | |||
*/ | |||
public boolean setNew( | |||
String property, Object value, PropertyHelper propertyHelper) { | |||
Map map = getMapForProperty(property); | |||
if (map == null) { | |||
return false; | |||
} | |||
Object currValue = map.get(property); | |||
if (currValue == NullReturn.NULL) { | |||
map.put(property, value); | |||
} | |||
return true; | |||
} | |||
/** | |||
* Set a property. | |||
* @param property the property's String "identifier". | |||
* @param value the value to set. | |||
* @param propertyHelper the invoking PropertyHelper. | |||
* @return true if this entity 'owns' the property. | |||
*/ | |||
public boolean set(String property, Object value, PropertyHelper propertyHelper) { | |||
Map map = getMapForProperty(property); | |||
if (map == null) { | |||
return false; | |||
} | |||
map.put(property, value); | |||
return true; | |||
} | |||
private Map getMapForProperty(String property) { | |||
for (Iterator i = stack.iterator(); i.hasNext();) { | |||
Map map = (Map) i.next(); | |||
if (map.get(property) != null) { | |||
return map; | |||
} | |||
} | |||
return null; | |||
} | |||
} | |||
@@ -0,0 +1,47 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You 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.apache.tools.ant.taskdefs; | |||
import org.apache.tools.ant.BuildException; | |||
import org.apache.tools.ant.Task; | |||
import org.apache.tools.ant.property.LocalProperties; | |||
/** | |||
* Task to create a local property in the current scope. | |||
*/ | |||
public class Local extends Task { | |||
private String name; | |||
/** | |||
* Set the name attribute. | |||
* @param name the name of the local property. | |||
*/ | |||
public void setName(String name) { | |||
this.name = name; | |||
} | |||
/** | |||
* Run the task. | |||
*/ | |||
public void execute() { | |||
if (name == null) { | |||
throw new BuildException("Missing attribute name"); | |||
} | |||
LocalProperties.get(getProject()).addLocal(name); | |||
} | |||
} |
@@ -37,6 +37,7 @@ import org.apache.tools.ant.Target; | |||
import org.apache.tools.ant.Task; | |||
import org.apache.tools.ant.TaskContainer; | |||
import org.apache.tools.ant.UnknownElement; | |||
import org.apache.tools.ant.property.LocalProperties; | |||
/** | |||
* The class to be placed in the ant type definition. | |||
@@ -390,6 +391,9 @@ public class MacroInstance extends Task implements DynamicAttribute, TaskContain | |||
// need to set the project on unknown element | |||
UnknownElement c = copy(macroDef.getNestedTask(), false); | |||
c.init(); | |||
LocalProperties localProperties | |||
= LocalProperties.get(getProject()); | |||
localProperties.enterScope(); | |||
try { | |||
c.perform(); | |||
} catch (BuildException ex) { | |||
@@ -403,6 +407,7 @@ public class MacroInstance extends Task implements DynamicAttribute, TaskContain | |||
} finally { | |||
presentElements = null; | |||
localAttributes = null; | |||
localProperties.exitScope(); | |||
} | |||
} | |||
} |
@@ -26,6 +26,7 @@ import org.apache.tools.ant.BuildException; | |||
import org.apache.tools.ant.Location; | |||
import org.apache.tools.ant.Task; | |||
import org.apache.tools.ant.TaskContainer; | |||
import org.apache.tools.ant.property.LocalProperties; | |||
import org.apache.tools.ant.util.StringUtils; | |||
/** | |||
@@ -451,6 +452,7 @@ public class Parallel extends Task | |||
*/ | |||
public void run() { | |||
try { | |||
LocalProperties.get(getProject()).copy(); | |||
thread = Thread.currentThread(); | |||
task.perform(); | |||
} catch (Throwable t) { | |||
@@ -23,6 +23,8 @@ import org.apache.tools.ant.BuildException; | |||
import org.apache.tools.ant.Task; | |||
import org.apache.tools.ant.TaskContainer; | |||
import org.apache.tools.ant.property.LocalProperties; | |||
/** | |||
* Sequential is a container task - it can contain other Ant tasks. The nested | |||
* tasks are simply executed in sequence. Sequential's primary use is to support | |||
@@ -57,9 +59,16 @@ public class Sequential extends Task implements TaskContainer { | |||
* @throws BuildException if one of the nested tasks fails. | |||
*/ | |||
public void execute() throws BuildException { | |||
for (Iterator i = nestedTasks.iterator(); i.hasNext();) { | |||
Task nestedTask = (Task) i.next(); | |||
nestedTask.perform(); | |||
LocalProperties localProperties | |||
= LocalProperties.get(getProject()); | |||
localProperties.enterScope(); | |||
try { | |||
for (Iterator i = nestedTasks.iterator(); i.hasNext();) { | |||
Task nestedTask = (Task) i.next(); | |||
nestedTask.perform(); | |||
} | |||
} finally { | |||
localProperties.exitScope(); | |||
} | |||
} | |||
} |
@@ -61,6 +61,7 @@ length=org.apache.tools.ant.taskdefs.Length | |||
loadfile=org.apache.tools.ant.taskdefs.LoadFile | |||
loadproperties=org.apache.tools.ant.taskdefs.LoadProperties | |||
loadresource=org.apache.tools.ant.taskdefs.LoadResource | |||
local=org.apache.tools.ant.taskdefs.Local | |||
macrodef=org.apache.tools.ant.taskdefs.MacroDef | |||
mail=org.apache.tools.ant.taskdefs.email.EmailTask | |||
manifest=org.apache.tools.ant.taskdefs.ManifestTask | |||
@@ -0,0 +1,86 @@ | |||
<?xml version="1.0"?> | |||
<!-- | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You 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. | |||
--> | |||
<project default="antunit" xmlns:au="antlib:org.apache.ant.antunit"> | |||
<import file="../antunit-base.xml" /> | |||
<property name="foo" value="foo" /> | |||
<target name="testBaseline"> | |||
<au:assertPropertyEquals name="foo" value="foo" /> | |||
</target> | |||
<target name="testTarget"> | |||
<au:assertPropertyEquals name="foo" value="foo" /> | |||
<local name="foo" /> | |||
<property name="foo" value="foo.target" /> | |||
<au:assertPropertyEquals name="foo" value="foo.target" /> | |||
</target> | |||
<target name="testSequential"> | |||
<sequential> | |||
<local name="foo" /> | |||
<property name="foo" value="foo.1" /> | |||
<sequential> | |||
<local name="foo" /> | |||
<property name="foo" value="foo.2" /> | |||
<au:assertPropertyEquals name="foo" value="foo.2" /> | |||
</sequential> | |||
<au:assertPropertyEquals name="foo" value="foo.1" /> | |||
</sequential> | |||
<au:assertPropertyEquals name="foo" value="foo" /> | |||
</target> | |||
<target name="testParallel"> | |||
<macrodef name="p"> | |||
<attribute name="value" /> | |||
<attribute name="sleep" default="0" /> | |||
<sequential> | |||
<local name="foo" /> | |||
<sleep seconds="@{sleep}" /> | |||
<property name="foo" value="@{value}" /> | |||
<au:assertPropertyEquals name="foo" value="@{value}" /> | |||
</sequential> | |||
</macrodef> | |||
<parallel> | |||
<p sleep="2" value="foo.a" /> | |||
<au:assertPropertyEquals name="foo" value="foo" /> | |||
<p sleep="1" value="foo.b" /> | |||
<au:assertPropertyEquals name="foo" value="foo" /> | |||
<p sleep="0" value="foo.c" /> | |||
<au:assertPropertyEquals name="foo" value="foo" /> | |||
</parallel> | |||
<au:assertPropertyEquals name="foo" value="foo" /> | |||
</target> | |||
<target name="testMacrodef"> | |||
<macrodef name="m"> | |||
<sequential> | |||
<local name="foo" /> | |||
<property name="foo" value="foo.x" /> | |||
<au:assertPropertyEquals name="foo" value="foo.x" /> | |||
</sequential> | |||
</macrodef> | |||
<m /> | |||
<au:assertPropertyEquals name="foo" value="foo" /> | |||
<m /> | |||
<au:assertPropertyEquals name="foo" value="foo" /> | |||
<m /> | |||
<au:assertPropertyEquals name="foo" value="foo" /> | |||
</target> | |||
</project> |