package com.intellij.lang.javascript.flex.build; import com.intellij.compiler.impl.BuildTargetScopeProvider; import com.intellij.compiler.options.CompileStepBeforeRun; import com.intellij.execution.configurations.RunConfiguration; import com.intellij.execution.configurations.RuntimeConfigurationError; import com.intellij.flex.FlexCommonUtils; import com.intellij.flex.build.FlexBuildTargetType; import com.intellij.flex.model.bc.TargetPlatform; import com.intellij.lang.javascript.flex.FlexBundle; import com.intellij.lang.javascript.flex.FlexModuleType; import com.intellij.lang.javascript.flex.actions.airpackage.AirPackageProjectParameters; import com.intellij.lang.javascript.flex.flexunit.FlexUnitRunConfiguration; import com.intellij.lang.javascript.flex.projectStructure.model.*; import com.intellij.lang.javascript.flex.projectStructure.model.FlexBuildConfiguration; import com.intellij.lang.javascript.flex.projectStructure.model.impl.Factory; import com.intellij.lang.javascript.flex.run.BCBasedRunnerParameters; import com.intellij.lang.javascript.flex.run.FlashRunConfiguration; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.compiler.CompileScope; import com.intellij.openapi.compiler.CompilerFilter; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.NullableComputable; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import org.jetbrains.annotations.NotNull; import org.jetbrains.jps.api.CmdlineProtoUtil; import java.util.*; import static org.jetbrains.jps.api.CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage.TargetTypeBuildScope; public class FlexBuildTargetScopeProvider extends BuildTargetScopeProvider { private static final Logger LOG = Logger.getInstance(FlexBuildTargetScopeProvider.class.getName()); static Collection<Pair<Module, FlexBuildConfiguration>> getModulesAndBCsToCompile(final CompileScope scope) throws ConfigurationException { final Collection<Pair<Module, FlexBuildConfiguration>> result = new HashSet<>(); final Collection<Pair<Module, FlexBuildConfiguration>> modulesAndBCsToCompile = FlexResourceBuildTargetScopeProvider.getBCsToCompileForPackaging(scope); final RunConfiguration runConfiguration = CompileStepBeforeRun.getRunConfiguration(scope); if (modulesAndBCsToCompile != null) { for (Pair<Module, FlexBuildConfiguration> moduleAndBC : modulesAndBCsToCompile) { if (!moduleAndBC.second.isSkipCompile()) { final FlexBuildConfiguration bcWithForcedDebugStatus = forceDebugStatus(moduleAndBC.first.getProject(), moduleAndBC.second); result.add(Pair.create(moduleAndBC.first, bcWithForcedDebugStatus)); appendBCDependencies(result, moduleAndBC.first, moduleAndBC.second); } } } else if (runConfiguration instanceof FlashRunConfiguration || runConfiguration instanceof FlexUnitRunConfiguration) { final BCBasedRunnerParameters params = runConfiguration instanceof FlashRunConfiguration ? ((FlashRunConfiguration)runConfiguration).getRunnerParameters() : ((FlexUnitRunConfiguration)runConfiguration).getRunnerParameters(); final Pair<Module, FlexBuildConfiguration> moduleAndBC; final Ref<RuntimeConfigurationError> exceptionRef = new Ref<>(); moduleAndBC = ApplicationManager.getApplication().runReadAction((NullableComputable<Pair<Module, FlexBuildConfiguration>>)() -> { try { return params.checkAndGetModuleAndBC(runConfiguration.getProject()); } catch (RuntimeConfigurationError e) { exceptionRef.set(e); return null; } }); if (!exceptionRef.isNull()) { throw new ConfigurationException(exceptionRef.get().getMessage(), FlexBundle.message("run.configuration.0", runConfiguration.getName())); } if (!moduleAndBC.second.isSkipCompile()) { result.add(moduleAndBC); appendBCDependencies(result, moduleAndBC.first, moduleAndBC.second); } } else { for (final Module module : scope.getAffectedModules()) { if (module.isDisposed() || ModuleType.get(module) != FlexModuleType.getInstance()) continue; for (final FlexBuildConfiguration bc : FlexBuildConfigurationManager.getInstance(module).getBuildConfigurations()) { if (!bc.isSkipCompile()) { result.add(Pair.create(module, bc)); } } } } return result; } private static FlexBuildConfiguration forceDebugStatus(final Project project, final FlexBuildConfiguration bc) { final boolean debug = getForcedDebugStatus(project, bc); // must not use getTemporaryCopyForCompilation() here because additional config file must not be merged with the generated one when compiling swf for release or AIR package final ModifiableFlexBuildConfiguration result = Factory.getCopy(bc); final String additionalOptions = FlexCommonUtils .removeOptions(bc.getCompilerOptions().getAdditionalOptions(), "debug", "compiler.debug"); result.getCompilerOptions().setAdditionalOptions(additionalOptions + " -debug=" + String.valueOf(debug)); return result; } public static boolean getForcedDebugStatus(final Project project, final FlexBuildConfiguration bc) { final boolean debug; if (bc.getTargetPlatform() == TargetPlatform.Mobile) { final AirPackageProjectParameters params = AirPackageProjectParameters.getInstance(project); if (bc.getAndroidPackagingOptions().isEnabled()) { debug = params.androidPackageType != AirPackageProjectParameters.AndroidPackageType.Release; } else { debug = params.iosPackageType == AirPackageProjectParameters.IOSPackageType.DebugOverNetwork; } } else { debug = false; } return debug; } private static void appendBCDependencies(final Collection<Pair<Module, FlexBuildConfiguration>> modulesAndBCs, final Module module, final FlexBuildConfiguration bc) throws ConfigurationException { for (final DependencyEntry entry : bc.getDependencies().getEntries()) { if (entry instanceof BuildConfigurationEntry) { final BuildConfigurationEntry bcEntry = (BuildConfigurationEntry)entry; final Module dependencyModule = bcEntry.findModule(); final FlexBuildConfiguration dependencyBC = dependencyModule == null ? null : bcEntry.findBuildConfiguration(); if (dependencyModule == null || dependencyBC == null) { throw new ConfigurationException(FlexBundle.message("bc.dependency.does.not.exist", bcEntry.getBcName(), bcEntry.getModuleName(), bc.getName(), module.getName())); } final Pair<Module, FlexBuildConfiguration> dependencyModuleAndBC = Pair.create(dependencyModule, dependencyBC); if (!dependencyBC.isSkipCompile()) { if (modulesAndBCs.add(dependencyModuleAndBC)) { appendBCDependencies(modulesAndBCs, dependencyModule, dependencyBC); } } } } } @NotNull public List<TargetTypeBuildScope> getBuildTargetScopes(@NotNull final CompileScope baseScope, @NotNull final CompilerFilter filter, @NotNull final Project project, boolean forceBuild) { final RunConfiguration runConfiguration = CompileStepBeforeRun.getRunConfiguration(baseScope); final Collection<Pair<Module, FlexBuildConfiguration>> bcsToCompileForPackaging = FlexResourceBuildTargetScopeProvider.getBCsToCompileForPackaging(baseScope); List<String> targetIds = new ArrayList<>(); try { for (Pair<Module, FlexBuildConfiguration> moduleAndBC : getModulesAndBCsToCompile(baseScope)) { final Module module = moduleAndBC.first; final FlexBuildConfiguration bc = moduleAndBC.second; if (bcsToCompileForPackaging != null && contains(bcsToCompileForPackaging, module, bc)) { final boolean forcedDebugStatus = getForcedDebugStatus(project, bc); targetIds.add(FlexCommonUtils.getBuildTargetId(module.getName(), bc.getName(), forcedDebugStatus)); } else if (bc.isTempBCForCompilation()) { LOG.assertTrue(runConfiguration instanceof FlashRunConfiguration || runConfiguration instanceof FlexUnitRunConfiguration, bc.getName()); final BCBasedRunnerParameters params = runConfiguration instanceof FlashRunConfiguration ? ((FlashRunConfiguration)runConfiguration).getRunnerParameters() : ((FlexUnitRunConfiguration)runConfiguration).getRunnerParameters(); LOG.assertTrue(params.getModuleName().equals(module.getName()), "Module name in run config: " + params.getModuleName() + ", expected: " + module.getName()); LOG.assertTrue(params.getBCName().equals(bc.getName()), "BC name in run config: " + params.getBCName() + ", expected: " + bc.getName()); targetIds.add(FlexCommonUtils.getBuildTargetIdForRunConfig(runConfiguration.getType().getId(), runConfiguration.getName())); } else { targetIds.add(FlexCommonUtils.getBuildTargetId(module.getName(), bc.getName(), null)); } } } catch (ConfigurationException e) { // can't happen because checked in ValidateFlashConfigurationsPrecompileTask LOG.error(e); } if (targetIds.isEmpty()) { return Collections.emptyList(); } return Collections.singletonList(CmdlineProtoUtil.createTargetsScope(FlexBuildTargetType.INSTANCE.getTypeId(), targetIds, forceBuild)); } private static boolean contains(final Collection<Pair<Module, FlexBuildConfiguration>> bcs, final Module module, final FlexBuildConfiguration bc) { for (Pair<Module, FlexBuildConfiguration> pair : bcs) { if (pair.first.getName().equals(module.getName()) && pair.second.getName().equals(bc.getName())) { return true; } } return false; } }