IDEA-90936 Force project make option before launch in run configuration
[idea/community.git] / java / execution / impl / src / com / intellij / compiler / options / CompileStepBeforeRun.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.compiler.options;
17
18 import com.intellij.execution.BeforeRunTask;
19 import com.intellij.execution.BeforeRunTaskProvider;
20 import com.intellij.execution.ExecutionBundle;
21 import com.intellij.execution.configurations.RunConfiguration;
22 import com.intellij.execution.configurations.RunConfigurationBase;
23 import com.intellij.execution.configurations.RunProfileWithCompileBeforeLaunchOption;
24 import com.intellij.execution.impl.ExecutionManagerImpl;
25 import com.intellij.execution.remote.RemoteConfiguration;
26 import com.intellij.execution.runners.ExecutionEnvironment;
27 import com.intellij.icons.AllIcons;
28 import com.intellij.openapi.actionSystem.DataContext;
29 import com.intellij.openapi.compiler.CompileContext;
30 import com.intellij.openapi.compiler.CompileScope;
31 import com.intellij.openapi.compiler.CompileStatusNotification;
32 import com.intellij.openapi.compiler.CompilerManager;
33 import com.intellij.openapi.diagnostic.Logger;
34 import com.intellij.openapi.module.Module;
35 import com.intellij.openapi.project.Project;
36 import com.intellij.openapi.util.Key;
37 import com.intellij.openapi.util.Ref;
38 import com.intellij.util.concurrency.Semaphore;
39 import org.jetbrains.annotations.NonNls;
40 import org.jetbrains.annotations.NotNull;
41 import org.jetbrains.annotations.Nullable;
42
43 import javax.swing.*;
44
45 /**
46  * @author spleaner
47  */
48 public class CompileStepBeforeRun extends BeforeRunTaskProvider<CompileStepBeforeRun.MakeBeforeRunTask> {
49   private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.options.CompileStepBeforeRun");
50   public static final Key<MakeBeforeRunTask> ID = Key.create("Make");
51   public static final Key<RunConfiguration> RUN_CONFIGURATION = Key.create("RUN_CONFIGURATION");
52   public static final Key<String> RUN_CONFIGURATION_TYPE_ID = Key.create("RUN_CONFIGURATION_TYPE_ID");
53
54   @NonNls protected static final String MAKE_PROJECT_ON_RUN_KEY = "makeProjectOnRun";
55
56   private final Project myProject;
57
58   public CompileStepBeforeRun(@NotNull final Project project) {
59     myProject = project;
60   }
61
62   public Key<MakeBeforeRunTask> getId() {
63     return ID;
64   }
65
66   @Override
67   public String getName() {
68     return ExecutionBundle.message("before.launch.compile.step");
69   }
70
71   @Override
72   public String getDescription(MakeBeforeRunTask task) {
73     return ExecutionBundle.message("before.launch.compile.step");
74   }
75
76   @Override
77   public Icon getIcon() {
78     return AllIcons.Actions.Compile;
79   }
80
81   @Override
82   public Icon getTaskIcon(MakeBeforeRunTask task) {
83     return AllIcons.Actions.Compile;
84   }
85
86   public MakeBeforeRunTask createTask(RunConfiguration runConfiguration) {
87     return !(runConfiguration instanceof RemoteConfiguration) && runConfiguration instanceof RunProfileWithCompileBeforeLaunchOption
88            ? new MakeBeforeRunTask()
89            : null;
90   }
91
92   public boolean configureTask(RunConfiguration runConfiguration, MakeBeforeRunTask task) {
93     return false;
94   }
95
96   @Override
97   public boolean canExecuteTask(RunConfiguration configuration, MakeBeforeRunTask task) {
98     return true;
99   }
100
101   public boolean executeTask(DataContext context, final RunConfiguration configuration, final ExecutionEnvironment env, MakeBeforeRunTask task) {
102     return doMake(myProject, configuration, env, false);
103   }
104
105   static boolean doMake(final Project myProject, final RunConfiguration configuration, final ExecutionEnvironment env, final boolean ignoreErrors) {
106     return doMake(myProject, configuration, env, ignoreErrors, Boolean.getBoolean(MAKE_PROJECT_ON_RUN_KEY));
107   }
108
109   static boolean doMake(final Project myProject, final RunConfiguration configuration, final ExecutionEnvironment env, final boolean ignoreErrors, final boolean forceMakeProject) {
110     if (!(configuration instanceof RunProfileWithCompileBeforeLaunchOption)) {
111       return true;
112     }
113
114     if (configuration instanceof RunConfigurationBase && ((RunConfigurationBase)configuration).excludeCompileBeforeLaunchOption()) {
115       return true;
116     }
117
118     final RunProfileWithCompileBeforeLaunchOption runConfiguration = (RunProfileWithCompileBeforeLaunchOption)configuration;
119     final Ref<Boolean> result = new Ref<Boolean>(Boolean.FALSE);
120     try {
121
122       final Semaphore done = new Semaphore();
123       done.down();
124       final CompileStatusNotification callback = new CompileStatusNotification() {
125         public void finished(final boolean aborted, final int errors, final int warnings, CompileContext compileContext) {
126           if ((errors == 0  || ignoreErrors) && !aborted) {
127             result.set(Boolean.TRUE);
128           }
129           done.up();
130         }
131       };
132
133       SwingUtilities.invokeAndWait(new Runnable() {
134         public void run() {
135           CompileScope scope;
136           final CompilerManager compilerManager = CompilerManager.getInstance(myProject);
137           if (forceMakeProject) {
138             // user explicitly requested whole-project make
139             scope = compilerManager.createProjectCompileScope(myProject);
140           }
141           else {
142             final Module[] modules = runConfiguration.getModules();
143             if (modules.length > 0) {
144               for (Module module : modules) {
145                 if (module == null) {
146                   LOG.error("RunConfiguration should not return null modules. Configuration=" + runConfiguration.getName() + "; class=" +
147                             runConfiguration.getClass().getName());
148                 }
149               }
150               scope = compilerManager.createModulesCompileScope(modules, true, true);
151             }
152             else {
153               scope = compilerManager.createProjectCompileScope(myProject);
154             }
155           }
156
157           if (!myProject.isDisposed()) {
158             scope.putUserData(RUN_CONFIGURATION, configuration);
159             scope.putUserData(RUN_CONFIGURATION_TYPE_ID, configuration.getType().getId());
160             ExecutionManagerImpl.EXECUTION_SESSION_ID_KEY.set(scope, ExecutionManagerImpl.EXECUTION_SESSION_ID_KEY.get(env));
161             compilerManager.make(scope, callback);
162           }
163           else {
164             done.up();
165           }
166         }
167       });
168       done.waitFor();
169     }
170     catch (Exception e) {
171       return false;
172     }
173
174     return result.get();
175   }
176
177   public boolean isConfigurable() {
178     return false;
179   }
180
181   @Nullable
182   public static RunConfiguration getRunConfiguration(final CompileContext context) {
183     return getRunConfiguration(context.getCompileScope());
184   }
185
186   @Nullable
187   public static RunConfiguration getRunConfiguration(final CompileScope compileScope) {
188     return compileScope.getUserData(RUN_CONFIGURATION);
189   }
190
191   public static class MakeBeforeRunTask extends BeforeRunTask<MakeBeforeRunTask> {
192     public MakeBeforeRunTask() {
193       super(ID);
194       setEnabled(true);
195     }
196   }
197 }