package com.intellij.flex.build; import com.intellij.flex.FlexCommonBundle; import com.intellij.flex.FlexCommonUtils; import com.intellij.flex.model.JpsFlexProjectLevelCompilerOptionsExtension; import com.intellij.flex.model.bc.*; import com.intellij.flex.model.bc.impl.JpsFlexBCState; import com.intellij.flex.model.bc.impl.JpsFlexCompilerOptionsImpl; import com.intellij.flex.model.run.JpsBCBasedRunnerParameters; import com.intellij.flex.model.run.JpsFlashRunConfigurationType; import com.intellij.flex.model.run.JpsFlexUnitRunConfigurationType; import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.PathUtilRt; import com.intellij.util.xmlb.XmlSerializer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.builders.*; import org.jetbrains.jps.builders.storage.BuildDataPaths; import org.jetbrains.jps.cmdline.ProjectDescriptor; import org.jetbrains.jps.incremental.CompileContext; import org.jetbrains.jps.indices.IgnoredFileIndex; import org.jetbrains.jps.indices.ModuleExcludeIndex; import org.jetbrains.jps.model.JpsModel; import org.jetbrains.jps.model.JpsProject; import org.jetbrains.jps.model.java.JavaSourceRootType; import org.jetbrains.jps.model.library.JpsLibrary; import org.jetbrains.jps.model.library.JpsOrderRootType; import org.jetbrains.jps.model.module.JpsModuleSourceRoot; import org.jetbrains.jps.model.runConfiguration.JpsRunConfigurationType; import org.jetbrains.jps.model.runConfiguration.JpsTypedRunConfiguration; import org.jetbrains.jps.util.JpsPathUtil; import java.io.File; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; public class FlexBuildTarget extends BuildTarget<BuildRootDescriptor> { private final @NotNull JpsFlexBuildConfiguration myBC; private final @NotNull String myId; private FlexBuildTarget(final @NotNull JpsFlexBuildConfiguration bc, final @NotNull String id) { super(FlexBuildTargetType.INSTANCE); myBC = bc; myId = id; } /** * @param forcedDebugStatus <code>true</code> or <code>false</code> means that this bc is compiled for further packaging and we need swf to have corresponding debug status; * <code>null</code> means that bc is compiled as is (i.e. as configured) without any modifications */ @NotNull public static FlexBuildTarget create(final @NotNull JpsFlexBuildConfiguration bc, final @Nullable Boolean forcedDebugStatus) { final String id = FlexCommonUtils.getBuildTargetId(bc.getModule().getName(), bc.getName(), forcedDebugStatus); if (forcedDebugStatus == null) { return new FlexBuildTarget(bc, id); } else { // 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 JpsFlexBuildConfiguration bcCopy = bc.getModule().getProperties().createCopy(bc); final String additionalOptions = FlexCommonUtils .removeOptions(bc.getCompilerOptions().getAdditionalOptions(), "debug", "compiler.debug"); bcCopy.getCompilerOptions().setAdditionalOptions(additionalOptions + " -debug=" + forcedDebugStatus.toString()); return new FlexBuildTarget(bcCopy, id); } } @Nullable public static FlexBuildTarget create(final JpsProject project, final @NotNull JpsRunConfigurationType<? extends JpsBCBasedRunnerParameters<?>> runConfigType, final @NotNull String runConfigName) { assert runConfigType instanceof JpsFlashRunConfigurationType || runConfigType instanceof JpsFlexUnitRunConfigurationType : runConfigType; final String runConfigTypeId = runConfigType instanceof JpsFlashRunConfigurationType ? JpsFlashRunConfigurationType.ID : JpsFlexUnitRunConfigurationType.ID; final JpsTypedRunConfiguration<? extends JpsBCBasedRunnerParameters<?>> runConfig = FlexCommonUtils.findRunConfiguration(project, runConfigType, runConfigName); final JpsFlexBuildConfiguration bc = runConfig == null ? null : runConfig.getProperties().getBC(project); final String id = FlexCommonUtils.getBuildTargetIdForRunConfig(runConfigTypeId, runConfigName); return bc == null ? null : new FlexBuildTarget(bc, id); } @Override @NotNull public String getId() { return myId; } @NotNull public JpsFlexBuildConfiguration getBC() { return myBC; } @Override public Collection<BuildTarget<?>> computeDependencies(BuildTargetRegistry targetRegistry, TargetOutputIndex outputIndex) { final ArrayList<BuildTarget<?>> result = new ArrayList<>(); final FlexResourceBuildTargetType type = FlexCommonUtils.isFlexUnitBC(myBC) ? FlexResourceBuildTargetType.TEST : FlexResourceBuildTargetType.PRODUCTION; result.add(new FlexResourceBuildTarget(type, myBC.getModule())); for (JpsFlexDependencyEntry entry : myBC.getDependencies().getEntries()) { if (entry instanceof JpsFlexBCDependencyEntry) { final JpsFlexBuildConfiguration dependencyBC = ((JpsFlexBCDependencyEntry)entry).getBC(); if (dependencyBC != null) { result.add(create(dependencyBC, null)); } } } result.trimToSize(); return result; } @Override @NotNull public List<BuildRootDescriptor> computeRootDescriptors(final JpsModel model, final ModuleExcludeIndex index, final IgnoredFileIndex ignoredFileIndex, final BuildDataPaths dataPaths) { final List<BuildRootDescriptor> result = new ArrayList<>(); final Collection<File> srcRoots = new ArrayList<>(); for (JpsModuleSourceRoot sourceRoot : myBC.getModule().getSourceRoots(JavaSourceRootType.SOURCE)) { final File root = JpsPathUtil.urlToFile(sourceRoot.getUrl()); result.add(new FlexSourceRootDescriptor(this, root)); srcRoots.add(root); } if (FlexCommonUtils.isFlexUnitBC(myBC)) { for (JpsModuleSourceRoot sourceRoot : myBC.getModule().getSourceRoots(JavaSourceRootType.TEST_SOURCE)) { final File root = JpsPathUtil.urlToFile(sourceRoot.getUrl()); result.add(new FlexSourceRootDescriptor(this, root)); srcRoots.add(root); } } for (final JpsFlexDependencyEntry entry : myBC.getDependencies().getEntries()) { if (entry instanceof JpsFlexBCDependencyEntry) { final JpsFlexBuildConfiguration dependencyBC = ((JpsFlexBCDependencyEntry)entry).getBC(); if (dependencyBC != null) { result.add(new FlexSourceRootDescriptor(this, new File(dependencyBC.getActualOutputFilePath()))); } } else if (entry instanceof JpsLibraryDependencyEntry) { final JpsLibrary library = ((JpsLibraryDependencyEntry)entry).getLibrary(); if (library != null) { for (String rootUrl : library.getRootUrls(JpsOrderRootType.COMPILED)) { result.add(new FlexSourceRootDescriptor(this, JpsPathUtil.urlToFile(rootUrl))); } } } } final BuildConfigurationNature nature = myBC.getNature(); if (nature.isWebPlatform() && nature.isApp() && myBC.isUseHtmlWrapper() && !myBC.getWrapperTemplatePath().isEmpty()) { addIfNotUnderRoot(result, new File(myBC.getWrapperTemplatePath()), srcRoots); } if (FlexCommonUtils.canHaveRLMsAndRuntimeStylesheets(myBC)) { for (String cssPath : myBC.getCssFilesToCompile()) { if (!cssPath.isEmpty()) { addIfNotUnderRoot(result, new File(cssPath), srcRoots); } } } if (!myBC.getCompilerOptions().getAdditionalConfigFilePath().isEmpty()) { addIfNotUnderRoot(result, new File(myBC.getCompilerOptions().getAdditionalConfigFilePath()), srcRoots); } if (nature.isApp()) { if (nature.isDesktopPlatform()) { addAirDescriptorPathIfCustom(result, myBC.getAirDesktopPackagingOptions(), srcRoots); } else if (nature.isMobilePlatform()) { if (myBC.getAndroidPackagingOptions().isEnabled()) { addAirDescriptorPathIfCustom(result, myBC.getAndroidPackagingOptions(), srcRoots); } if (myBC.getIosPackagingOptions().isEnabled()) { addAirDescriptorPathIfCustom(result, myBC.getIosPackagingOptions(), srcRoots); } } } return result; } private void addIfNotUnderRoot(final List<BuildRootDescriptor> descriptors, final File file, final Collection<File> roots) { for (File root : roots) { if (FileUtil.isAncestor(root, file, false)) { return; } } descriptors.add(new FlexSourceRootDescriptor(this, file)); } private void addAirDescriptorPathIfCustom(final List<BuildRootDescriptor> descriptors, final JpsAirPackagingOptions packagingOptions, final Collection<File> srcRoots) { if (!packagingOptions.isUseGeneratedDescriptor() && !packagingOptions.getCustomDescriptorPath().isEmpty()) { addIfNotUnderRoot(descriptors, new File(packagingOptions.getCustomDescriptorPath()), srcRoots); } } @Override @Nullable public BuildRootDescriptor findRootDescriptor(final String rootId, final BuildRootIndex rootIndex) { for (BuildRootDescriptor descriptor : rootIndex.getTargetRoots(this, null)) { if (descriptor.getRootId().equals(rootId)) { return descriptor; } } return null; } @Override @NotNull public String getPresentableName() { return FlexCommonBundle.message("bc.0.module.1", myBC.getName(), myBC.getModule().getName()); } @Override @NotNull public Collection<File> getOutputRoots(CompileContext context) { return Collections.singleton(new File(PathUtilRt.getParentPath(myBC.getActualOutputFilePath()))); } @Override public void writeConfiguration(ProjectDescriptor pd, final PrintWriter out) { out.println("id: " + myId); out.println(JDOMUtil.writeElement(XmlSerializer.serialize(JpsFlexBCState.getState(myBC)))); final JpsFlexModuleOrProjectCompilerOptions moduleOptions = myBC.getModule().getProperties().getModuleLevelCompilerOptions(); out.println(JDOMUtil.writeElement(XmlSerializer.serialize(((JpsFlexCompilerOptionsImpl)moduleOptions).getState()))); final JpsFlexModuleOrProjectCompilerOptions projectOptions = JpsFlexProjectLevelCompilerOptionsExtension.getProjectLevelCompilerOptions(myBC.getModule().getProject()); out.println(JDOMUtil.writeElement(XmlSerializer.serialize(((JpsFlexCompilerOptionsImpl)projectOptions).getState()))); } public String toString() { return myId; } public boolean equals(final Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; final FlexBuildTarget target = (FlexBuildTarget)o; if (!myId.equals(target.myId)) return false; return true; } public int hashCode() { return myId.hashCode(); } }