package jetbrains.mps.ide.make;
/*Generated by MPS */
import com.intellij.openapi.progress.Task;
import java.util.concurrent.Future;
import jetbrains.mps.make.script.IResult;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
import jetbrains.mps.make.service.CoreMakeTask;
import org.jetbrains.annotations.Nullable;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import jetbrains.mps.make.dependencies.MakeSequence;
import jetbrains.mps.make.script.IScriptController;
import jetbrains.mps.messages.IMessageHandler;
import com.intellij.openapi.progress.PerformInBackgroundOption;
import com.intellij.openapi.progress.ProgressIndicator;
import jetbrains.mps.ide.ThreadUtils;
import jetbrains.mps.progress.ProgressMonitorAdapter;
import org.jetbrains.mps.openapi.util.ProgressMonitor;
import jetbrains.mps.messages.Message;
import jetbrains.mps.messages.MessageKind;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.CancellationException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class MakeTask extends Task.Backgroundable implements Future<IResult> {
private final CountDownLatch myLatch = new CountDownLatch(1);
private final AtomicReference<MakeTask.TaskState> myState = new AtomicReference<MakeTask.TaskState>(MakeTask.TaskState.NOT_STARTED);
private final CoreMakeTask coreTask;
private boolean isCanceled = false;
public MakeTask(@Nullable Project project, @NotNull String title, MakeSequence makeSeq, IScriptController ctl, IMessageHandler mh, PerformInBackgroundOption bgoption) {
super(project, title, true, bgoption);
// XXX might be nice to pass CoreMakeTask here, instead of long list of arguments to construct one.
// however not it's too much of refactoring for WorkbenchMakeTask
coreTask = new MakeTask.WorkbenchMakeTask(title, makeSeq, ctl, mh);
}
@Override
public void run(@NotNull final ProgressIndicator pi) {
if (myState.compareAndSet(MakeTask.TaskState.NOT_STARTED, MakeTask.TaskState.RUNNING)) {
if (ThreadUtils.isInEDT()) {
coreTask.run(new ProgressMonitorAdapter(pi));
} else {
this.spawnMakeThreadThenDoRunRelayingLog(new ProgressMonitorAdapter(pi));
}
}
}
private void spawnMakeThreadThenDoRunRelayingLog(final ProgressMonitor monitor) {
ThreadGroup tg = new ThreadGroup("MPS Make Thread Group") {
@Override
public void uncaughtException(Thread thread, Throwable th) {
Message msg = new Message(MessageKind.ERROR, String.format("Uncaught %s during make in thread %s", th.getClass().getSimpleName(), thread.getName()));
msg.setException(th);
coreTask.getMessageHandler().handle(msg);
}
};
// the flag "daemon" must be set in order for ThreadGroup to be garbage-collected
tg.setDaemon(true);
Thread makeThread = new Thread(tg, new Runnable() {
@Override
public void run() {
coreTask.run(monitor);
}
}, "MPS Make Thread");
makeThread.start();
do {
try {
makeThread.join();
} catch (InterruptedException ie) {
}
} while (makeThread.isAlive());
}
@Override
public void onCancel() {
isCanceled = true;
}
@Override
public boolean cancel(boolean b) {
return false;
}
@Override
public boolean isCancelled() {
return myState.get() == MakeTask.TaskState.CANCELLED;
}
@Override
public boolean isDone() {
return myState.get() != MakeTask.TaskState.NOT_STARTED && myState.get() != MakeTask.TaskState.RUNNING;
}
@Override
public IResult get() throws InterruptedException, ExecutionException {
myLatch.await();
if (myState.get() == MakeTask.TaskState.CANCELLED) {
throw new CancellationException();
}
return coreTask.getResult();
}
@Override
public IResult get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
myLatch.await(timeout, unit);
if (myState.get() == MakeTask.TaskState.CANCELLED) {
throw new CancellationException();
}
return coreTask.getResult();
}
protected void displayInfo(String info) {
}
protected void aboutToStart() {
}
protected void done() {
}
public class WorkbenchMakeTask extends CoreMakeTask {
public WorkbenchMakeTask(@NotNull String title, MakeSequence makeSeq, IScriptController ctl, IMessageHandler mh) {
super(title, makeSeq, ctl, mh);
}
@Override
protected void reconcile() {
MakeTask.this.myState.set(MakeTask.TaskState.DONE);
try {
if (isCanceled || coreTask.getResult() == null) {
MakeTask.this.myState.set(MakeTask.TaskState.CANCELLED);
}
super.reconcile();
} finally {
myLatch.countDown();
done();
}
}
@Override
protected void doRun(ProgressMonitor monitor) {
super.doRun(monitor);
MakeTask.this.myState.set(MakeTask.TaskState.INDETERMINATE);
}
@Override
protected void displayInfo(String info) {
MakeTask.this.displayInfo(info);
}
@Override
protected void aboutToStart() {
MakeTask.this.aboutToStart();
}
}
private enum TaskState {
NOT_STARTED(),
RUNNING(),
DONE(),
CANCELLED(),
INDETERMINATE()
}
}