blob: c7ff7548fa3f234c31c2db12be33bb9d9c884693 [file] [log] [blame]
package org.apache.tools.ant.listener;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.ant.debugger.Auditor;
import org.apache.ant.debugger.DebugCommandSet;
import org.apache.ant.debugger.DebugPrompt;
import org.apache.ant.debugger.DebugSupport;
import org.apache.ant.debugger.DefaultAuditor;
import org.apache.tools.ant.BuildEvent;
import org.apache.tools.ant.BuildListener;
import org.apache.tools.ant.MagicNames;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.PropertyDebugHelper;
import org.apache.tools.ant.PropertyHelper;
import org.apache.tools.ant.Target;
import org.apache.tools.ant.input.InputHandler;
// The input-listener should itself be pluggable
/*
* We can probably build up a stack of targets in execution to allow dumping a stack of a target
* when a break point occurs?
*
* This class also doubles as a DebugSupport Command that can be used to add new targets / properties
* to debug at runtime.
*/
public class DebuggerListener implements BuildListener, DebugSupport {
/**
* The project being debugged.
*/
protected Project project = null;
/**
* List of all targets at which break points have been applied.
*/
protected List debugtargets = new LinkedList();
/**
* Indicates if this listener instance has been initialized.
*/
protected boolean inited = false;
/**
* Debugger instance.
*/
protected DebugPrompt prompt = null;
/**
* Contains the current target being executed.
*
* TODO: This is not being used now but there is a possibility for its use.
*/
protected Target currentTarget = null;
/**
* An Auditor instance that keeps track of all changes to properties
* identified by the user.
*
*
* TODO: The auditor instance itself should be pluggable, I think to allow
* different PropertyHelpers to be used.
*/
protected Auditor auditor = null;
/**
* InputHandler instance that may be different than the configured one.
*/
protected InputHandler inputHandler;
/**
* {@link DebugCommandSet} instance that is a container for all
* {@link DebugSupport} commands that may be used with this listener.
*/
protected DebugCommandSet commandHandler = new DebugCommandSet();
// List of all break point facilities to be available
// ==================================================
/**
* Target break point property name
*/
public static final String DEBUG_TARGET_PROPERTY = "ant.debug.target";
/**
* Exception break point property name
*/
public static final String DEBUG_EXCEPTION_PROPERTY = "ant.debug.exception";
/**
* Break point when the value of a property changes or is attempted to be
* changed.
*/
public static final String DEBUG_PROPERTY_CHANGE_PROPERTY = "ant.debug.property";
/**
* Request to audit all attempted changes to a property
*/
public static final String AUDIT_PROPERTY_PROPERTY = "ant.audit.property";
// End of all available break points
// =================================
public void init(BuildEvent event) {
project = event.getProject();
project.log("Attaching DebuggerListener to the build.");
}
public void buildFinished(BuildEvent event) {
// Anything to do?
}
protected Map getDefaultCommandSupport() {
if (auditor instanceof DebugSupport) {
Map defaults = new HashMap();
defaults.put("trace", auditor);
defaults.put("break", this);
defaults.put("watch", this);
return defaults;
}
return null;
}
public void buildStarted(BuildEvent event) {
// set audit property helper that will help keep track of properties
// being set everywhere.
project = event.getProject();
PropertyHelper helper = new PropertyDebugHelper();
helper.setProject(project);
auditor = new DefaultAuditor();
((PropertyDebugHelper) helper).setAuditor(auditor);
// Is it better to set it as a project helper or as a delegate to the
// helper?
project.addReference(MagicNames.REFID_PROPERTY_HELPER, helper);
commandHandler.setProject(project);
commandHandler.init(getDefaultCommandSupport());
prompt = new DebugPrompt(project, commandHandler);
auditor.setPrompt(prompt);
// this is how the debugging starts
prompt.prompt("Type /? to get any help.");
}
public void messageLogged(BuildEvent event) {
// Do Nothing
}
public void targetFinished(BuildEvent event) {
currentTarget = null;
}
public void targetStarted(BuildEvent event) {
currentTarget = event.getTarget();
Target target = event.getTarget();
if (debugtargets.contains(target.getName())) {
prompt.prompt("Break Point at Target: " + target.getName());
}
}
public void taskFinished(BuildEvent event) {
}
public void taskStarted(BuildEvent event) {
}
/*
* The following section of code customizes this class to double up as a
* DebugSupport command instance so that it is possible to add
* target/property break points at runtime.
*/
/*
* TODO INFO command is yet to be implemented. The idea is to output a list
* of all target break points and properties being monitored with their
* statuses (Pending / Done etc).
*/
public void execute(Project project, String[] params) {
if (params.length > 1 && "/?".equals(params[1])) {
printUsage(project);
return;
}
if (params.length < 2) {
project.log("Incorrect Parameters");
printUsage(project);
return;
}
String command = params[0];
if ("break".equalsIgnoreCase(command)) {
for (int i = 1; i < params.length; i++) {
debugtargets.add(params[i]);
project.log("Added BreakPoint at Target: " + params[i]);
}
} else if ("watch".equalsIgnoreCase(command)) {
/*
* watch points for properties
*/
for (int i = 1; i < params.length; i++) {
auditor.addPropertyForAudits(params[i], project);
project.log("Added BreakPoint at Property: " + params[i]);
}
} else if ("info".equalsIgnoreCase(command)) {
// TODO show all break points and watch points here
}
}
public void printUsage(Project project) {
project.log("Usage: break property some.property.1 some.property.2");
project.log(" break target some.target.1 some.target.2");
project
.log("The above command will add all properties/targets as breakpoints.");
}
}