GP-882: Fixing attach action. Refactoring and error handling.

This commit is contained in:
Dan
2021-04-23 11:46:46 -04:00
parent 3456422e8c
commit f3453b9f2c
2 changed files with 62 additions and 176 deletions
@@ -23,6 +23,7 @@ import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import javax.swing.*;
import javax.swing.tree.TreePath;
@@ -1315,34 +1316,37 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter
refresh("");
}
protected <T extends TargetObject> void performAction(ActionContext context,
boolean fallbackRoot, Class<T> cls,
Function<T, CompletableFuture<Void>> func, String errorMsg) {
TargetObject obj = getObjectFromContext(context);
if (obj == null && fallbackRoot) {
obj = root.getTargetObject();
}
if (!isLocalOnly()) {
DebugModelConventions.findSuitable(cls, obj).thenCompose(t -> {
return func.apply(t);
}).exceptionally(DebuggerResources.showError(getComponent(), errorMsg));
}
else {
T t = cls.cast(obj);
func.apply(t).exceptionally(DebuggerResources.showError(getComponent(), errorMsg));
}
}
public void performQuickLaunch(ActionContext context) {
if (currentProgram == null) {
return;
}
TargetObject obj = getObjectFromContext(context);
if (obj == null) {
obj = root.getTargetObject();
}
// TODO: A generic or pluggable way of deriving the launch arguments
CompletableFuture<? extends TargetLauncher> fl =
DebugModelConventions.findSuitable(TargetLauncher.class, obj);
fl.thenCompose(launcher -> {
return launcher.launch(Map.of(TargetCmdLineLauncher.CMDLINE_ARGS_NAME,
currentProgram.getExecutablePath()));
}).exceptionally(e -> {
Msg.showError(this, getComponent(), "Could not launch", e);
return null;
});
performAction(context, true, TargetLauncher.class, launcher -> {
// TODO: A generic or pluggable way of deriving the launch arguments
return launcher.launch(Map.of(
TargetCmdLineLauncher.CMDLINE_ARGS_NAME, currentProgram.getExecutablePath()));
}, "Couldn't launch");
}
public void performLaunch(ActionContext context) {
TargetObject obj = getObjectFromContext(context);
if (obj == null) {
obj = root.getTargetObject();
}
CompletableFuture<? extends TargetLauncher> fl =
DebugModelConventions.findSuitable(TargetLauncher.class, obj);
fl.thenCompose(launcher -> {
performAction(context, true, TargetLauncher.class, launcher -> {
if (currentProgram != null) {
// TODO: A generic or pluggable way of deriving the default arguments
String path = currentProgram.getExecutablePath();
@@ -1360,30 +1364,22 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter
return AsyncUtils.NIL;
}
return launcher.launch(args);
}).exceptionally(ex -> {
Msg.showError(this, null, "Launch", "Problem during launch", ex);
return null;
});
}, "Couldn't launch");
}
public void performAttach(ActionContext context) {
TargetObject obj = getObjectFromContext(context);
AtomicReference<TargetAttacher> attacher = new AtomicReference<>();
AsyncUtils.sequence(TypeSpec.VOID).then(seq -> {
DebugModelConventions.findSuitable(TargetAttacher.class, obj).handle(seq::next);
}, attacher).then(seq -> {
TargetAttacher a = attacher.get();
attachDialog.setAttacher(a);
performAction(context, false, TargetAttacher.class, attacher -> {
attachDialog.setAttacher(attacher);
if (obj instanceof TargetAttachable) {
TargetAttachable attachable = (TargetAttachable) obj;
long pid = attachDialog.getPid(attachable);
a.attach(pid);
return attacher.attach((TargetAttachable) obj);
}
else {
attachDialog.fetchAndDisplayAttachable();
tool.showDialog(attachDialog);
return AsyncUtils.NIL;
}
}).finish();
}, "Couldn't attach");
}
public void performReattach(ActionContext context) {
@@ -1391,13 +1387,10 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter
if (!(obj instanceof TargetAttachable)) {
return;
}
AtomicReference<TargetObject> parent = new AtomicReference<>();
AsyncUtils.sequence(TypeSpec.VOID).then(seq -> {
DebugModelConventions.findSuitable(TargetAttacher.class, obj).handle(seq::next);
}, parent).then(seq -> {
TargetAttacher attacher = parent.get().as(TargetAttacher.class);
attacher.attach((TargetAttachable) obj).handle(seq::nextIgnore);
}).finish();
// NB. This doesn't really mean anything in local-only actions mode
DebugModelConventions.findSuitable(TargetAttacher.class, obj).thenCompose(attacher -> {
return attacher.attach((TargetAttachable) obj);
}).exceptionally(DebuggerResources.showError(getComponent(), "Couldn't re-attach"));
}
public void startRecording(TargetProcess targetObject, boolean prompt) {
@@ -1426,171 +1419,73 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter
}
public void performDetach(ActionContext context) {
TargetObject obj = getObjectFromContext(context);
if (!isLocalOnly()) {
DebugModelConventions.findSuitable(TargetDetachable.class, obj)
.thenAccept(detachable -> {
detachable.detach();
})
.exceptionally(DebuggerResources.showError(getComponent(), "Couldn't detach"));
}
else {
TargetDetachable detachable = (TargetDetachable) obj;
detachable.detach();
}
performAction(context, false, TargetDetachable.class, TargetDetachable::detach,
"Couldn't detach");
}
public void performKill(ActionContext context) {
TargetObject obj = getObjectFromContext(context);
if (!isLocalOnly()) {
DebugModelConventions.findSuitable(TargetKillable.class, obj).thenAccept(killable -> {
killable.kill();
}).exceptionally(DebuggerResources.showError(getComponent(), "Couldn't kill"));
}
else {
TargetKillable killable = (TargetKillable) obj;
killable.kill();
}
performAction(context, false, TargetKillable.class, TargetKillable::kill, "Couldn't kill");
}
public void performStartRecording(ActionContext context) {
TargetObject obj = getObjectFromContext(context);
if (!isLocalOnly()) {
DebugModelConventions.findSuitable(TargetProcess.class, obj).thenAccept(process -> {
TargetProcess valid = DebugModelConventions.liveProcessOrNull(process);
if (valid != null) {
startRecording(valid, true);
}
}).exceptionally(DebuggerResources.showError(getComponent(), "Couldn't record"));
}
else {
TargetProcess valid = DebugModelConventions.liveProcessOrNull(obj);
performAction(context, false, TargetProcess.class, proc -> {
TargetProcess valid = DebugModelConventions.liveProcessOrNull(proc);
if (valid != null) {
startRecording(valid, true);
}
}
return AsyncUtils.NIL;
}, "Couldn't record");
}
public void performResume(ActionContext context) {
TargetObject obj = getObjectFromContext(context);
if (!isLocalOnly()) {
DebugModelConventions.findSuitable(TargetResumable.class, obj).thenAccept(resumable -> {
resumable.resume();
}).exceptionally(DebuggerResources.showError(getComponent(), "Couldn't resume"));
}
else {
TargetResumable resumable = (TargetResumable) obj;
resumable.resume();
}
performAction(context, false, TargetResumable.class, TargetResumable::resume,
"Couldn't resume");
}
public void performInterrupt(ActionContext context) {
TargetObject obj = getObjectFromContext(context);
if (!isLocalOnly()) {
DebugModelConventions.findSuitable(TargetInterruptible.class, obj)
.thenAccept(interruptible -> {
interruptible.interrupt();
})
.exceptionally(
DebuggerResources.showError(getComponent(), "Couldn't interrupt"));
}
else {
TargetInterruptible interruptible = (TargetInterruptible) obj;
interruptible.interrupt();
}
performAction(context, false, TargetInterruptible.class, TargetInterruptible::interrupt,
"Couldn't interrupt");
}
public void performStepInto(ActionContext context) {
TargetObject obj = getObjectFromContext(context);
if (!isLocalOnly()) {
DebugModelConventions.findSuitable(TargetSteppable.class, obj).thenAccept(steppable -> {
steppable.step();
}).exceptionally(DebuggerResources.showError(getComponent(), "Couldn't step"));
}
else {
TargetSteppable steppable = (TargetSteppable) obj;
steppable.step();
}
performAction(context, false, TargetSteppable.class, TargetSteppable::step,
"Couldn't step into");
}
public void performStepOver(ActionContext context) {
TargetObject obj = getObjectFromContext(context);
if (!isLocalOnly()) {
DebugModelConventions.findSuitable(TargetSteppable.class, obj).thenAccept(steppable -> {
steppable.step(TargetStepKind.OVER);
}).exceptionally(DebuggerResources.showError(getComponent(), "Couldn't step"));
}
else {
TargetSteppable steppable = (TargetSteppable) obj;
steppable.step(TargetStepKind.OVER);
}
performAction(context, false, TargetSteppable.class, s -> s.step(TargetStepKind.OVER),
"Couldn't step over");
}
public void performStepFinish(ActionContext context) {
TargetObject obj = getObjectFromContext(context);
if (!isLocalOnly()) {
DebugModelConventions.findSuitable(TargetSteppable.class, obj).thenAccept(steppable -> {
steppable.step(TargetStepKind.FINISH);
}).exceptionally(DebuggerResources.showError(getComponent(), "Couldn't step"));
}
else {
TargetSteppable steppable = (TargetSteppable) obj;
steppable.step(TargetStepKind.FINISH);
}
performAction(context, false, TargetSteppable.class, s -> s.step(TargetStepKind.FINISH),
"Couldn't step finish");
}
public void performStepLast(ActionContext context) {
TargetObject obj = getObjectFromContext(context);
if (!isLocalOnly()) {
DebugModelConventions.findSuitable(TargetSteppable.class, obj).thenAccept(steppable -> {
steppable.step(TargetStepKind.EXTENDED);
}).exceptionally(DebuggerResources.showError(getComponent(), "Couldn't step"));
}
else {
TargetSteppable steppable = (TargetSteppable) obj;
performAction(context, false, TargetSteppable.class, s -> {
if (extendedStep.equals("")) {
steppable.step(TargetStepKind.EXTENDED);
return s.step(TargetStepKind.EXTENDED);
}
else {
Map<String, String> args = new HashMap<String, String>();
args.put("Command", extendedStep);
steppable.step(args);
return s.step(Map.of("Command", extendedStep));
}
}
}, "Couldn't step extended(" + extendedStep + ")");
}
public void performSetBreakpoint(ActionContext context) {
TargetObject obj = getObjectFromContext(context);
if (!isLocalOnly()) {
DebugModelConventions.findSuitable(TargetBreakpointSpecContainer.class, obj)
.thenAccept(suitable -> {
breakpointDialog.setContainer(suitable);
tool.showDialog(breakpointDialog);
})
.exceptionally(
DebuggerResources.showError(getComponent(), "Couldn't set breakpoint"));
}
else {
TargetBreakpointSpecContainer container = (TargetBreakpointSpecContainer) obj;
performAction(context, false, TargetBreakpointSpecContainer.class, container -> {
breakpointDialog.setContainer(container);
tool.showDialog(breakpointDialog);
}
return AsyncUtils.NIL;
}, "Couldn't set breakpoint");
}
public void initiateConsole(ActionContext context) {
TargetObject obj = getObjectFromContext(context);
if (!isLocalOnly()) {
DebugModelConventions.findSuitable(TargetInterpreter.class, obj)
.thenAccept(interpreter -> {
getPlugin().showConsole(interpreter);
})
.exceptionally(
DebuggerResources.showError(getComponent(), "Couldn't launch interpreter"));
}
else {
TargetInterpreter interpreter = (TargetInterpreter) obj;
performAction(context, false, TargetInterpreter.class, interpreter -> {
getPlugin().showConsole(interpreter);
}
return AsyncUtils.NIL;
}, "Couldn't show interpreter");
}
public boolean isStopped(ActionContext context) {
@@ -119,7 +119,6 @@ public class DebuggerAttachDialog extends DialogComponentProvider {
if (proc == null) {
return;
}
//long pid = getPid(proc);
setStatusText("Attaching");
attacher.attach(proc).thenAccept(__ -> {
close();
@@ -130,14 +129,6 @@ public class DebuggerAttachDialog extends DialogComponentProvider {
});
}
public long getPid(TargetAttachable proc) {
String name = proc.getName();
name = name.substring(1, name.length() - 1);
long pid = Long.parseLong(name, 16);
return pid;
}
@SuppressWarnings("unchecked")
public void fetchAndDisplayAttachable() {
AtomicReference<TargetObject> available = new AtomicReference<>();
AtomicReference<Map<String, ? extends TargetObject>> procs = new AtomicReference<>();