org.moe.idea.compiler.MOECompileTask.java Source code

Java tutorial

Introduction

Here is the source code for org.moe.idea.compiler.MOECompileTask.java

Source

/*
Copyright (C) 2016 Migeran
    
Licensed 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.moe.idea.compiler;

import com.intellij.compiler.options.CompileStepBeforeRun;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.openapi.compiler.CompileContext;
import com.intellij.openapi.compiler.CompileTask;
import com.intellij.openapi.compiler.CompilerMessageCategory;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.util.Key;
import com.intellij.util.ui.UIUtil;
import org.moe.idea.maven.MOEMavenBuildTask;
import org.moe.idea.runconfig.configuration.MOERunConfiguration;
import org.moe.idea.ui.DeviceChooserDialog;
import org.moe.idea.ui.MOEToolWindow;
import org.moe.idea.utils.ModuleUtils;
import org.moe.idea.utils.logger.LoggerFactory;

import java.io.IOException;

public class MOECompileTask implements CompileTask {
    private static final Logger LOG = LoggerFactory.getLogger(MOECompileTask.class);

    private boolean isOpenDialog;
    private boolean canceled;

    @Override
    public boolean execute(CompileContext context) {
        RunConfiguration c = context.getCompileScope().getUserData(CompileStepBeforeRun.RUN_CONFIGURATION);

        if (!(c instanceof MOERunConfiguration)) {
            return true;
        }

        final MOERunConfiguration runConfig = (MOERunConfiguration) c;
        isOpenDialog = runConfig.getOpenDeploymentTargetDialog();
        canceled = false;
        runConfig.setCanceled(canceled);

        final MOEToolWindow toolWindow = MOEToolWindow.getInstance(runConfig.getProject());
        UIUtil.invokeAndWaitIfNeeded(new Runnable() {
            @Override
            public void run() {
                toolWindow.clear();
                if (isOpenDialog) {
                    DeviceChooserDialog dialog = new DeviceChooserDialog(runConfig.module(), runConfig);
                    dialog.show();
                    if (dialog.getExitCode() != DialogWrapper.OK_EXIT_CODE) {
                        canceled = true;
                        runConfig.setCanceled(canceled);
                    }
                    isOpenDialog = false;
                }
            }
        });
        try {

            while (isOpenDialog) {
                Thread.sleep(100);
            }

            boolean isMaven = ModuleUtils.isMOEMavenModule(runConfig.module());

            // Start progress
            ProgressIndicator progress = context.getProgressIndicator();
            context.getProgressIndicator().pushState();
            progress.setText("Building MOE application");

            if (canceled) {
                toolWindow.balloon(MessageType.INFO, "BUILD CANCELED");
                return true;
            }

            if (!isMaven) {

                final CompileThread compileThread = new CompileThread(runConfig, context);
                compileThread.start();

                context.addMessage(CompilerMessageCategory.INFORMATION, "Building " + runConfig.moduleName(), null,
                        -1, -1);

                // Wait for completion
                while (compileThread.isAlive() && !progress.isCanceled()) {
                    compileThread.join(1000);
                }
                if (compileThread.isAlive() && progress.isCanceled()) {
                    compileThread.interrupt();
                    compileThread.join(1000);
                }

                // Re-throw error
                if (compileThread.throwable != null) {
                    throw compileThread.throwable;
                }

                // Show on failure
                if (compileThread.returnCode != 0) {
                    if (!compileThread.canceled) {
                        toolWindow.balloon(MessageType.ERROR, "BUILD FAILED");
                        context.addMessage(CompilerMessageCategory.ERROR, "Multi-OS Engine module build failed",
                                null, -1, -1, toolWindow.getNavigatable());
                    } else {
                        toolWindow.balloon(MessageType.INFO, "BUILD CANCELED");
                    }
                    return false;
                }
            } else {
                MOEMavenBuildTask mavenTask = new MOEMavenBuildTask(runConfig, "Building " + runConfig.moduleName(),
                        true);
                boolean result = mavenTask.runTask();
                if (!result) {
                    toolWindow.balloon(MessageType.ERROR, "BUILD FAILED");
                    context.addMessage(CompilerMessageCategory.ERROR, "Multi-OS Engine module build failed", null,
                            -1, -1, toolWindow.getNavigatable());
                    return false;
                }
            }

        } catch (Throwable t) {
            toolWindow.balloon(MessageType.ERROR, "BUILD FAILED");
            LOG.error("Failed to compile module", t);
            context.addMessage(CompilerMessageCategory.ERROR,
                    "Multi-OS Engine module build failed, an internal error occurred", null, -1, -1);
            return false;
        } finally {
            context.getProgressIndicator().popState();
        }
        return true;
    }

    private class CompileThread extends Thread {
        private final MOERunConfiguration runConfig;
        private final CompileContext compileContext;
        private int returnCode = -1;
        private OSProcessHandler handler;
        private Throwable throwable;
        private boolean canceled;

        private CompileThread(MOERunConfiguration runConfig, CompileContext compileContext) {
            if (runConfig == null) {
                throw new NullPointerException();
            }
            if (compileContext == null) {
                throw new NullPointerException();
            }
            this.runConfig = runConfig;
            this.compileContext = compileContext;
        }

        @Override
        public void run() {
            try {
                unsafeRun();
            } catch (Throwable t) {
                throwable = t;
            }
        }

        private void unsafeRun() throws ExecutionException, IOException, InterruptedException {
            // Configure Gradle
            final MOEGradleRunner gradleRunner = new MOEGradleRunner(runConfig);
            final boolean isDebug = runConfig.getActionType().equals("Debug");
            final GeneralCommandLine commandLine = gradleRunner.construct(isDebug, false);
            handler = new OSProcessHandler(commandLine);
            handler.setShouldDestroyProcessRecursively(true);

            // Configure output
            final MOEToolWindow toolWindow = MOEToolWindow.getInstance(runConfig.getProject());
            handler.addProcessListener(new ProcessAdapter() {
                @Override
                public void onTextAvailable(ProcessEvent event, Key outputType) {
                    if (ProcessOutputTypes.STDERR.equals(outputType)) {
                        toolWindow.error(event.getText());
                    } else if (ProcessOutputTypes.STDOUT.equals(outputType)) {
                        toolWindow.log(event.getText());
                    } else {
                        compileContext.addMessage(CompilerMessageCategory.INFORMATION, "MOE: " + event.getText(),
                                null, -1, -1, toolWindow.getNavigatable());
                    }
                }
            });
            handler.startNotify();

            // Start and wait
            handler.waitFor();
            returnCode = handler.getProcess().exitValue();
        }

        @Override
        public void interrupt() {
            canceled = true;
            if (handler != null) {
                handler.destroyProcess();
                int timeout = 2000;
                while (timeout > 0 && !handler.isProcessTerminated()) {
                    timeout -= 100;
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        break;
                    }
                }
                if (handler.isProcessTerminated()) {
                    return;
                }
            }
            super.interrupt();
        }
    }
}