/* * Copyright 2000-2012 JetBrains s.r.o. * * 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.napile.idea.thermit.config.execution; import java.util.List; import java.util.concurrent.TimeUnit; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.napile.idea.thermit.ThermitBundle; import org.napile.idea.thermit.config.AntBuildFile; import org.napile.idea.thermit.config.AntBuildFileBase; import org.napile.idea.thermit.config.AntBuildListener; import org.napile.idea.thermit.config.impl.BuildFileProperty; import com.intellij.concurrency.JobScheduler; import com.intellij.execution.CantRunException; import com.intellij.execution.ExecutionException; import com.intellij.execution.configurations.CommandLineBuilder; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.execution.junit.JUnitProcessHandler; import com.intellij.execution.junit2.segments.OutputPacketProcessor; import com.intellij.execution.process.OSProcessHandler; import com.intellij.execution.process.ProcessAdapter; import com.intellij.execution.process.ProcessEvent; import com.intellij.execution.util.ExecutionErrorDialog; import com.intellij.history.LocalHistory; import com.intellij.ide.macro.Macro; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.encoding.EncodingProjectManager; import com.intellij.openapi.wm.StatusBar; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowId; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.openapi.wm.WindowManager; public final class ExecutionHandler { private static final Logger LOG = Logger.getInstance("#com.intellij.thermit.execution.ExecutionHandler"); @NonNls public static final String PARSER_JAR = "xerces1.jar"; private ExecutionHandler() { } /** * @param antBuildListener should not be null. Use {@link org.napile.idea.thermit.config.AntBuildListener#NULL} */ public static void runBuild(final AntBuildFileBase buildFile, String[] targets, @Nullable final AntBuildMessageView buildMessageViewToReuse, final DataContext dataContext, List<BuildFileProperty> additionalProperties, @NotNull final AntBuildListener antBuildListener) { FileDocumentManager.getInstance().saveAllDocuments(); final AntCommandLineBuilder builder = new AntCommandLineBuilder(); final AntBuildMessageView messageView; final GeneralCommandLine commandLine; synchronized(builder) { Project project = buildFile.getProject(); try { builder.setBuildFile(buildFile.getAllOptions(), VfsUtil.virtualToIoFile(buildFile.getVirtualFile())); builder.calculateProperties(dataContext, additionalProperties); builder.addTargets(targets); builder.getCommandLine().setCharset(EncodingProjectManager.getInstance(buildFile.getProject()).getDefaultCharset()); messageView = prepareMessageView(buildMessageViewToReuse, buildFile, targets); commandLine = CommandLineBuilder.createFromJavaParameters(builder.getCommandLine()); messageView.setBuildCommandLine(commandLine.getCommandLineString()); } catch(RunCanceledException e) { e.showMessage(project, ThermitBundle.message("run.ant.erorr.dialog.title")); antBuildListener.buildFinished(AntBuildListener.FAILED_TO_RUN, 0); return; } catch(CantRunException e) { ExecutionErrorDialog.show(e, ThermitBundle.message("cant.run.ant.erorr.dialog.title"), project); antBuildListener.buildFinished(AntBuildListener.FAILED_TO_RUN, 0); return; } catch(Macro.ExecutionCancelledException e) { antBuildListener.buildFinished(AntBuildListener.ABORTED, 0); return; } catch(Throwable e) { antBuildListener.buildFinished(AntBuildListener.FAILED_TO_RUN, 0); LOG.error(e); return; } } final boolean startInBackground = buildFile.isRunInBackground(); new Task.Backgroundable(null, ThermitBundle.message("ant.build.progress.dialog.title"), true) { public boolean shouldStartInBackground() { return startInBackground; } public void run(@NotNull final ProgressIndicator indicator) { try { runBuild(indicator, messageView, buildFile, antBuildListener, commandLine); } catch(Throwable e) { LOG.error(e); antBuildListener.buildFinished(AntBuildListener.FAILED_TO_RUN, 0); } } }.queue(); } private static void runBuild(final ProgressIndicator progress, @NotNull final AntBuildMessageView errorView, @NotNull final AntBuildFile buildFile, @NotNull final AntBuildListener antBuildListener, @NotNull GeneralCommandLine commandLine) { final Project project = buildFile.getProject(); final long startTime = System.currentTimeMillis(); LocalHistory.getInstance().putSystemLabel(project, ThermitBundle.message("ant.build.local.history.label", buildFile.getName())); final JUnitProcessHandler handler; try { handler = JUnitProcessHandler.runCommandLine(commandLine); } catch(final ExecutionException e) { ApplicationManager.getApplication().invokeLater(new Runnable() { public void run() { ExecutionErrorDialog.show(e, ThermitBundle.message("could.not.start.process.erorr.dialog.title"), project); } }); antBuildListener.buildFinished(AntBuildListener.FAILED_TO_RUN, 0); return; } processRunningAnt(progress, handler, errorView, buildFile, startTime, antBuildListener); handler.waitFor(); } private static void processRunningAnt(final ProgressIndicator progress, final JUnitProcessHandler handler, final AntBuildMessageView errorView, final AntBuildFile buildFile, final long startTime, final AntBuildListener antBuildListener) { final Project project = buildFile.getProject(); final StatusBar statusbar = WindowManager.getInstance().getStatusBar(project); if(statusbar != null) { statusbar.setInfo(ThermitBundle.message("ant.build.started.status.message")); } final CheckCancelTask checkCancelTask = new CheckCancelTask(progress, handler); checkCancelTask.start(0); final OutputParser parser = OutputParser2.attachParser(project, handler, errorView, progress, buildFile); handler.addProcessListener(new ProcessAdapter() { public void processTerminated(ProcessEvent event) { final long buildTime = System.currentTimeMillis() - startTime; checkCancelTask.cancel(); parser.setStopped(true); final OutputPacketProcessor dispatcher = handler.getErr().getEventsDispatcher(); errorView.buildFinished(progress != null && progress.isCanceled(), buildTime, antBuildListener, dispatcher); ApplicationManager.getApplication().invokeLater(new Runnable() { public void run() { if(project.isDisposed()) { return; } errorView.removeProgressPanel(); ToolWindow toolWindow = ToolWindowManager.getInstance(project).getToolWindow(ToolWindowId.MESSAGES_WINDOW); if(toolWindow != null) { // can be null if project is closed toolWindow.activate(null, false); } } }, ModalityState.NON_MODAL); } }); handler.startNotify(); } static final class CheckCancelTask implements Runnable { private final ProgressIndicator myProgressIndicator; private final OSProcessHandler myProcessHandler; private volatile boolean myCanceled; public CheckCancelTask(ProgressIndicator progressIndicator, OSProcessHandler process) { myProgressIndicator = progressIndicator; myProcessHandler = process; } public void cancel() { myCanceled = true; } public void run() { if(!myCanceled) { try { myProgressIndicator.checkCanceled(); start(50); } catch(ProcessCanceledException e) { myProcessHandler.destroyProcess(); } } } public void start(final long delay) { JobScheduler.getScheduler().schedule(this, delay, TimeUnit.MILLISECONDS); } } private static AntBuildMessageView prepareMessageView(@Nullable AntBuildMessageView buildMessageViewToReuse, AntBuildFileBase buildFile, String[] targets) throws RunCanceledException { AntBuildMessageView messageView; if(buildMessageViewToReuse != null) { messageView = buildMessageViewToReuse; messageView.emptyAll(); } else { messageView = AntBuildMessageView.openBuildMessageView(buildFile.getProject(), buildFile, targets); if(messageView == null) { throw new RunCanceledException(ThermitBundle.message("canceled.by.user.error.message")); } } return messageView; } }