blob: 59eae5d581dc7cc266c007fc7ca168065a68c8a7 [file] [log] [blame]
Index: src/main/org/apache/tools/ant/helper/ProjectHelper2.java
===================================================================
--- src/main/org/apache/tools/ant/helper/ProjectHelper2.java (revision 1132928)
+++ src/main/org/apache/tools/ant/helper/ProjectHelper2.java (working copy)
@@ -27,6 +27,7 @@
import org.apache.tools.ant.Target;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.UnknownElement;
+import org.apache.tools.ant.DebugTask;
import org.apache.tools.ant.types.Resource;
import org.apache.tools.ant.types.resources.FileProvider;
import org.apache.tools.ant.types.resources.URLProvider;
@@ -923,7 +924,11 @@
target.setProject(project);
target.setLocation(new Location(context.getLocator()));
context.addTarget(target);
-
+ boolean isTarget = false;
+ if(!(target instanceof ExtensionPoint)) {
+ isTarget = true;
+ }
+
for (int i = 0; i < attrs.getLength(); i++) {
String attrUri = attrs.getURI(i);
if (attrUri != null && !attrUri.equals("") && !attrUri.equals(uri)) {
@@ -1015,6 +1020,18 @@
}
}
}
+
+ if(isTarget && name.equals(project.getBreakAt())) {
+ // If the current element is a target and it is the same one as specified
+ // for Ant to suspend execution at, then add an internal dependency on
+ // the Debug Target
+ DebugTask.createDebugTarget(project);
+
+ // add this dependency to the end of the dependency list so that this target
+ // executes immediately ahead of the -breakAt target
+ target.addDependency(DebugTask.DEBUG_TARGET_NAME);
+ }
+
if (!isInIncludeMode && context.isIgnoringProjectTag()
&& (prefix = getTargetPrefix(context)) != null) {
// In an imported file (and not completely
Index: src/main/org/apache/tools/ant/Project.java
===================================================================
--- src/main/org/apache/tools/ant/Project.java (revision 1132928)
+++ src/main/org/apache/tools/ant/Project.java (working copy)
@@ -210,6 +210,19 @@
private boolean keepGoingMode = false;
/**
+ * Contains the target to break the execution at.
+ */
+ protected String breakAt;
+
+ public void setBreakAt(String breakAt) {
+ this.breakAt = breakAt;
+ }
+
+ public String getBreakAt() {
+ return breakAt;
+ }
+
+ /**
* Set the input handler.
*
* @param handler the InputHandler instance to use for gathering input.
Index: src/main/org/apache/tools/ant/DebugTask.java
===================================================================
--- src/main/org/apache/tools/ant/DebugTask.java (revision 0)
+++ src/main/org/apache/tools/ant/DebugTask.java (revision 0)
@@ -0,0 +1,329 @@
+package org.apache.tools.ant;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ComponentHelper;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Target;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.input.DefaultInputHandler;
+import org.apache.tools.ant.input.InputHandler;
+import org.apache.tools.ant.input.InputRequest;
+import org.apache.tools.ant.taskdefs.PathConvert;
+import org.apache.tools.ant.taskdefs.Property;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * A stand alone debug task that plugs into the build through projecthelper
+ * class by injecting a dependency at the end of a target. This is a POC and
+ * does not yet work for Extension-Points.
+ */
+public class DebugTask extends Task {
+ /**
+ * Debugger prompt
+ */
+ public static final String PROMPT = "DEBUGGER> ";
+
+ /**
+ * Standard target name for the internal debugger
+ */
+ public static final String DEBUG_TARGET_NAME = "-internal-debugger";
+
+ /*
+ * A static final debug target that is injected as a dependency. We may need
+ * to have more than one such target if we are to allow multiple
+ * break-points in the build.
+ */
+ private static final Target debugTarget = new Target();
+
+ /*
+ * Set of all commands that can be interpreted at runtime.
+ */
+ private static Set supportedCommands = new HashSet();
+
+ static {
+ // add any more commands to be supported here
+ // if need be, this can be considered to be
+ // moved to a separate properties file
+ supportedCommands.add("locate");
+ supportedCommands.add("inspect");
+ supportedCommands.add("return");
+ }
+
+ public void execute() throws BuildException {
+ // expect input here
+ InputRequest ir = new InputRequest(PROMPT);
+ InputHandler ih = new DefaultInputHandler();
+ String command = null;
+ getProject().log(
+ StringUtils.LINE_SEP
+ + "-------- Ant Command Line Debugger --------"
+ + StringUtils.LINE_SEP + StringUtils.LINE_SEP);
+
+ // keep accepting inputs, until the user enters the return command
+ do {
+ ih.handleInput(ir);
+ command = ir.getInput();
+ handleCommand(command);
+ getProject().log(""); // log a new line
+ } while (!"return".equals(command));
+
+ // resume build execution on this
+ getProject().log(
+ StringUtils.LINE_SEP
+ + "--------- Resuming Ant Execution ----------"
+ + StringUtils.LINE_SEP);
+ }
+
+ /**
+ * Static method to create a runtime-debug target. For purposes of Command
+ * Line Debugger (CLD), the target returned by this method, and identified
+ * by DEBUG_TARGET_NAME must be added at the end of the dependency list of
+ * the target where the break point exists.
+ *
+ * @param project
+ * @return
+ */
+ public static Target createDebugTarget(Project project) {
+ // see what is the best value for the Location to assume?
+ // Location loc = new Location(??);
+
+ debugTarget.setProject(project);
+ debugTarget.setName(DEBUG_TARGET_NAME);
+ project.addTarget(debugTarget);
+ // create an instance of debug task and attach it to this project
+ Task debugtask = project.createTask("debug");
+ debugtask.setProject(project);
+ debugtask.setTaskName("Debugger");
+ debugTarget.addTask(debugtask);
+ return debugTarget;
+ }
+
+ /*
+ * Interprets user input and decides if the command is supported or should
+ * be rejected.
+ */
+ protected void handleCommand(String command) {
+ if (command == null || command.trim().length() == 0) {
+ getProject().log("Invalid command. Use /? for more information.");
+ }
+ command = command.trim();
+ if (command.equals("/?")) {
+ printUsage();
+ return;
+ }
+
+ String[] tokens = command.split(" ");
+ if (!supportedCommands.contains(tokens[0])) {
+ printUsage();
+ return;
+ }
+
+ DebugSupport[] debuggers = new DebugSupport[] { new NoOp(),
+ new Inspector(), new Locator() };
+ DebugSupport selected = null;
+ for (int j = 0; j < debuggers.length; j++) {
+ if (debuggers[j].commandSupported(tokens[0]))
+ selected = debuggers[j];
+ }
+ selected.execute(getProject(), tokens);
+ }
+
+ protected void printUsage() {
+ // log all help stuff here
+ getProject()
+ .log(
+ "You may use one of the following commands: locate, inspect, return");
+ getProject()
+ .log(
+ "Type the command followed by /? for more information. Eg. inspect /?");
+ }
+
+ protected static List searchTask(Class expectedTaskClass, Project project) {
+ List result = new ArrayList();
+ for (Iterator iterator = project.getTargets().values().iterator(); iterator
+ .hasNext();) {
+ Target t = (Target) iterator.next();
+ for (int i = 0; i < t.getTasks().length; i++) {
+ Task task = t.getTasks()[i];
+ Class taskClass = ComponentHelper.getComponentHelper(project)
+ .getComponentClass(task.getTaskType());
+ // will need to see in what cases it could return a null type
+ // perhaps failing when the task is using a custom antlib
+ // defined task
+ if (taskClass != null && taskClass.equals(expectedTaskClass)) {
+ result.add(task);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * An interface for supporting debug commands.
+ */
+ public static interface DebugSupport {
+
+ /**
+ * Check if this command is supported.
+ *
+ * @param command
+ * @return
+ */
+ public boolean commandSupported(String command);
+
+ /**
+ * Main execution body of the class. Pass all command parameters.
+ *
+ * @param project
+ * @param params
+ */
+ public void execute(Project project, String[] params);
+
+ /**
+ * Prints usage of the command.
+ *
+ * @param project
+ */
+ public void printUsage(Project project);
+
+ }
+
+ /**
+ * Used to implement commands that should not be handled by
+ * {@link DebugSupport} at all. Example, the 'return' command
+ */
+ public static final class NoOp implements DebugSupport {
+
+ public boolean commandSupported(String command) {
+ return "return".equalsIgnoreCase(command);
+ }
+
+ public void execute(Project project, String[] params) {
+ // do nothing
+ }
+
+ public void printUsage(Project project) {
+ };
+ }
+
+ /**
+ * Locates properties / paths in static build sources
+ */
+ public static final class Locator implements DebugSupport {
+
+ public boolean commandSupported(String command) {
+ return "locate".equalsIgnoreCase(command);
+ }
+
+ public void execute(Project project, String[] params) {
+ // the command syntax is 'locate property some.property'
+ // or 'locate path some.path
+ if (params.length != 3 || "/?".equals(params[1])) {
+ printUsage(project);
+ return;
+ }
+
+ List matches = null;
+ String key = null;
+ if ("property".equalsIgnoreCase(params[1])) {
+ // locate and publish the property
+ matches = DebugTask.searchTask(Property.class, project);
+ key = "name";
+ } else if ("path".equalsIgnoreCase(params[1])) {
+ // locate and publish the path
+ matches = DebugTask.searchTask(Path.class, project);
+ key = "id";
+ } else {
+ // see if any other component may be supported
+ project.log("Unexpected component: " + params[1]);
+ project.log("Supported components are property, path.");
+ return;
+ }
+
+ // probably accept some kind of a query from end user and select the
+ // target object based on the query
+ for (Iterator iterator = matches.iterator(); iterator.hasNext();) {
+ Task task = (Task) iterator.next();
+ // display attributes
+ Map attributeMap = task.getWrapper().getAttributeMap();
+ if (!params[2].equals(attributeMap.get(key))) {
+ continue;
+ }
+ String value = (String) attributeMap.get("value");
+ project.log("Detected a property by name [" + params[2]
+ + "]. Build file value: " + value);
+ // and their respected location
+ project.log("Located at: " + task.getLocation().toString());
+ }
+ }
+
+ public void printUsage(Project project) {
+ project.log("Incorrect Parameters");
+ project.log("Usage: locate property/path propertyname/pathname");
+ }
+ }
+
+ /**
+ * Inspects the current value of a property, path or some reference.
+ */
+ public static final class Inspector implements DebugSupport {
+
+ public boolean commandSupported(String command) {
+ return "inspect".equalsIgnoreCase(command);
+ }
+
+ public void execute(Project project, String[] params) {
+ if (params.length < 3 || "/?".equals(params[1])) {
+ printUsage(project);
+ }
+
+ if ("property".equalsIgnoreCase(params[1])) {
+ // show all matches for a property
+ Object value = PropertyHelper.getProperty(project, params[2]);
+ if (value != null) {
+ project.log("Detected a property by name [" + params[1]
+ + "]. Current value: " + value);
+ } else {
+ project.log("Found no such property.");
+ }
+ } else if ("path".equalsIgnoreCase(params[1])) {
+ // look optional component
+ // the remaining part of the string could be:
+ // id=<someid> or refid=<somerefid>
+ Object ref = project.getReference(params[2]);
+ if (ref instanceof ResourceCollection) {
+ if (ref != null) {
+ PathConvert path = (PathConvert) project
+ .createTask("pathconvert");
+ path.setProject(project);
+ path.setPathSep(StringUtils.LINE_SEP + " - ");
+ path.add((ResourceCollection) ref);
+ path.execute();
+ } else {
+ project.log("No path-reference found for " + params[2]);
+ }
+ } else {
+ project.log("No path found for reference id: " + params[2]);
+ }
+ }
+
+ }
+
+ public void printUsage(Project project) {
+ project.log("Incorrect Parameters");
+ project.log("Usage: inspect property some.property");
+ project.log(" inspect path path.id");
+ }
+ }
+}
Property changes on: src\main\org\apache\tools\ant\DebugTask.java
___________________________________________________________________
Added: svn:eol-style
+ native
Index: src/main/org/apache/tools/ant/taskdefs/defaults.properties
===================================================================
--- src/main/org/apache/tools/ant/taskdefs/defaults.properties (revision 1132928)
+++ src/main/org/apache/tools/ant/taskdefs/defaults.properties (working copy)
@@ -230,3 +230,4 @@
renameext=org.apache.tools.ant.taskdefs.optional.RenameExtensions
starteam=org.apache.tools.ant.taskdefs.optional.scm.AntStarTeamCheckOut
style=org.apache.tools.ant.taskdefs.XSLTProcess
+debug=org.apache.tools.ant.DebugTask
Index: src/main/org/apache/tools/ant/Main.java
===================================================================
--- src/main/org/apache/tools/ant/Main.java (revision 1132928)
+++ src/main/org/apache/tools/ant/Main.java (working copy)
@@ -149,6 +149,11 @@
private boolean proxy = false;
/**
+ * Target at which to break execution sequence
+ */
+ private String breakAt = null;
+
+ /**
* Prints the message of the Throwable if it (the message) is not
* <code>null</code>.
*
@@ -382,6 +387,8 @@
throw new BuildException(msg);
} else if (arg.equals("-autoproxy")) {
proxy = true;
+ } else if (arg.equals("-breakAt")) {
+ breakAt = args[++i];
} else if (arg.startsWith("-")) {
// we don't have any more args to recognize!
String msg = "Unknown argument: " + arg;
@@ -761,7 +768,7 @@
project.init();
-
+ project.setBreakAt(breakAt);
// resolve properties
PropertyHelper propertyHelper
= (PropertyHelper) PropertyHelper.getPropertyHelper(project);