package com.intellij.flex;
import com.intellij.execution.configurations.CommandLineTokenizer;
import com.intellij.execution.process.BaseOSProcessHandler;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.flex.model.JpsFlexCompilerProjectExtension;
import com.intellij.flex.model.bc.*;
import com.intellij.flex.model.sdk.JpsFlexSdkType;
import com.intellij.flex.model.sdk.JpsFlexmojosSdkProperties;
import com.intellij.flex.model.sdk.JpsFlexmojosSdkType;
import com.intellij.flex.model.sdk.RslUtil;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.PairConsumer;
import com.intellij.util.PathUtilRt;
import com.intellij.util.SystemProperties;
import gnu.trove.THashMap;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.incremental.Utils;
import org.jetbrains.jps.model.JpsElement;
import org.jetbrains.jps.model.JpsProject;
import org.jetbrains.jps.model.JpsSimpleElement;
import org.jetbrains.jps.model.java.JdkVersionDetector;
import org.jetbrains.jps.model.library.sdk.JpsSdk;
import org.jetbrains.jps.model.module.JpsModule;
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.model.serialization.JpsModelSerializationDataService;
import org.jetbrains.jps.util.JpsPathUtil;
import java.io.*;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class FlexCommonUtils {
public static final String AIR_NAMESPACE_BASE = "http://ns.adobe.com/air/application/";
//keep in sync with OutputLogger.ERROR_PATTERN from BuiltInFlexCompiler project !!!
public static final Pattern ERROR_PATTERN =
Pattern.compile("(.*?)(\\(\\D.*\\))?(?:\\((-?\\d+)\\))?: ?(?:col: (-?\\d+):?)? (Warning|Error): (.*)");
public static final String LOCALE_TOKEN = "{locale}";
public static final Pattern XMX_PATTERN = Pattern.compile("(.* )?-Xmx([0-9]+)[mM]( .*)?");
public static final String AIR_SDK_VERSION_PREFIX = "AIR SDK ";
public static final String FLEX_UNIT_LAUNCHER = "____FlexUnitLauncher";
public static final String SDK_TOOLS_ENCODING = "UTF-8";
public static final String OUT_OF_MEMORY = "java.lang.OutOfMemoryError";
public static final String JAVA_HEAP_SPACE = "Java heap space";
public static final String COULD_NOT_CREATE_JVM = "Could not create the Java virtual machine";
public static final String HTML_WRAPPER_TEMPLATE_FILE_NAME = "index.template.html";
public static final String SWF_MACRO = "${swf}";
public static final String TITLE_MACRO = "${title}";
public static final String APPLICATION_MACRO = "${application}";
public static final String BG_COLOR_MACRO = "${bgcolor}";
public static final String WIDTH_MACRO = "${width}";
public static final String HEIGHT_MACRO = "${height}";
public static final String VERSION_MAJOR_MACRO = "${version_major}";
public static final String VERSION_MINOR_MACRO = "${version_minor}";
public static final String VERSION_REVISION_MACRO = "${version_revision}";
public static final String TITLE_ATTR = "pageTitle";
public static final String BG_COLOR_ATTR = "backgroundColor";
public static final String WIDTH_ATTR = "width";
public static final String HEIGHT_ATTR = "height";
public static final String FLEXUNIT_4_TEST_RUNNER = "com.intellij.flexunit.runner.TestRunner4";
public static final String FLEXUNIT_1_TEST_RUNNER = "com.intellij.flexunit.runner.TestRunner1";
private static final String MODULE_PREFIX = "Module: ";
private static final String BC_PREFIX = "\tBC: ";
private static final String RUN_CONFIG_TYPE_PREFIX = "Run config type: ";
private static final String RUN_CONFIG_NAME_PREFIX = "\tName: ";
private static final String FORCED_DEBUG_STATUS = "\tForced debug status: ";
private static final Logger LOG = Logger.getInstance(FlexCommonUtils.class.getName());
public static final boolean KEEP_TEMP_FILES = Boolean.parseBoolean(System.getProperty("idea.keep.flex.temporary.files"));
public static final Pattern AIR_VERSION_PATTERN = Pattern.compile("[0-9]+\\.[0-9]+(\\.[0-9]+)*");
private static final Map<Pair<String, Long>, String> ourAdtJarPathAndTimestampToVersion = new THashMap<>();
public static boolean isSourceFile(final String fileName) {
final String ext = FileUtilRt.getExtension(fileName);
return ext.equalsIgnoreCase("as") || ext.equalsIgnoreCase("mxml") || ext.equalsIgnoreCase("fxg");
}
public static boolean canHaveResourceFiles(final BuildConfigurationNature nature) {
return nature.isApp();
}
public static boolean isFlexUnitBC(final JpsFlexBuildConfiguration bc) {
return bc.isTempBCForCompilation() && bc.getMainClass().endsWith(FLEX_UNIT_LAUNCHER);
}
public static boolean isRuntimeStyleSheetBC(final JpsFlexBuildConfiguration bc) {
return bc.isTempBCForCompilation() && bc.getMainClass().toLowerCase().endsWith(".css");
}
public static boolean isRLMTemporaryBC(final JpsFlexBuildConfiguration bc) {
return bc.isTempBCForCompilation() && bc.getOutputType() == OutputType.RuntimeLoadedModule;
}
public static boolean canHaveRLMsAndRuntimeStylesheets(final JpsFlexBuildConfiguration bc) {
return canHaveRLMsAndRuntimeStylesheets(bc.getOutputType(), bc.getTargetPlatform());
}
public static boolean canHaveRLMsAndRuntimeStylesheets(final OutputType outputType, final TargetPlatform targetPlatform) {
return outputType == OutputType.Application && targetPlatform != TargetPlatform.Mobile;
}
@Nullable
public static String getBCSpecifier(final JpsFlexBuildConfiguration bc) {
if (!bc.isTempBCForCompilation()) return null;
if (isFlexUnitBC(bc)) return "flexunit";
if (isRLMTemporaryBC(bc)) return "module " + StringUtil.getShortName(bc.getMainClass());
if (isRuntimeStyleSheetBC(bc)) return PathUtilRt.getFileName(bc.getMainClass());
return StringUtil.getShortName(bc.getMainClass());
}
public static String getTempFlexConfigsDirPath() {
return getTempFlexConfigsDirPath(FileUtil.getTempDirectory());
}
public static String getTempFlexConfigsDirPath(final String tempDirPath) {
return FileUtil.toSystemIndependentName(tempDirPath) + "/" +
"IntelliJ_IDEA"; //ApplicationNamesInfo.getInstance().getFullProductName().replace(' ', '_');
}
/**
* @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
*/
public static String getBuildTargetId(final String moduleName, final String bcName, final @Nullable Boolean forcedDebugStatus) {
return MODULE_PREFIX + moduleName + BC_PREFIX + bcName + FORCED_DEBUG_STATUS + forcedDebugStatus;
}
public static String getBuildTargetIdForRunConfig(final String runConfigTypeId, final String runConfigName) {
return RUN_CONFIG_TYPE_PREFIX + runConfigTypeId + RUN_CONFIG_NAME_PREFIX + runConfigName;
}
@Nullable
public static Pair<String, String> getRunConfigTypeIdAndNameByBuildTargetId(final String buildTargetId) {
if (buildTargetId.startsWith(RUN_CONFIG_TYPE_PREFIX)) {
final int index = buildTargetId.indexOf(RUN_CONFIG_NAME_PREFIX);
assert index > 0 : buildTargetId;
return Pair.create(buildTargetId.substring(RUN_CONFIG_TYPE_PREFIX.length(), index),
buildTargetId.substring(index + RUN_CONFIG_NAME_PREFIX.length()));
}
return null;
}
/**
* @return <code>Trinity.first</code> - module name<br/>
* <code>Trinity.second</code> - BC name<br/>
* <code>Trinity.third</code> - forced debug status: <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
*/
@Nullable
public static Trinity<String, String, Boolean> getModuleAndBCNameAndForcedDebugStatusByBuildTargetId(final String buildTargetId) {
if (buildTargetId.startsWith(MODULE_PREFIX)) {
final int bcIndex = buildTargetId.indexOf(BC_PREFIX);
final int forceDebugIndex = buildTargetId.indexOf(FORCED_DEBUG_STATUS);
assert bcIndex > 0 && forceDebugIndex > bcIndex : buildTargetId;
final String moduleName = buildTargetId.substring(MODULE_PREFIX.length(), bcIndex);
final String bcName = buildTargetId.substring(bcIndex + BC_PREFIX.length(), forceDebugIndex);
final String forcedDebugText = buildTargetId.substring(forceDebugIndex + FORCED_DEBUG_STATUS.length());
final Boolean forcedDebugStatus = forcedDebugText.equalsIgnoreCase("true")
? Boolean.TRUE
: forcedDebugText.equalsIgnoreCase("false")
? Boolean.FALSE
: null;
return Trinity.create(moduleName, bcName, forcedDebugStatus);
}
return null;
}
@Nullable
public static <P extends JpsElement> JpsTypedRunConfiguration<P> findRunConfiguration(final @NotNull JpsProject project,
final @NotNull JpsRunConfigurationType<P> runConfigType,
final @NotNull String runConfigName) {
for (JpsTypedRunConfiguration<P> runConfig : project.getRunConfigurations(runConfigType)) {
if (runConfigName.equals(runConfig.getName())) {
return runConfig;
}
}
return null;
}
public static List<String> getOptionValues(final String commandLine, final String... optionAndAliases) {
if (StringUtil.isEmpty(commandLine)) {
return Collections.emptyList();
}
final List<String> result = new LinkedList<>();
for (CommandLineTokenizer tokenizer = new CommandLineTokenizer(commandLine); tokenizer.hasMoreTokens(); ) {
final String token = tokenizer.nextToken();
for (String option : optionAndAliases) {
if (token.startsWith("-" + option + "=") || token.startsWith("-" + option + "+=")) {
result.addAll(StringUtil.split(token.substring(token.indexOf("=") + 1), ","));
}
else if (token.equals("-" + option) && tokenizer.countTokens() > 0) {
if (tokenizer.countTokens() > 0) {
String nextToken;
while (tokenizer.hasMoreTokens() && canBeCompilerOptionValue(nextToken = tokenizer.peekNextToken())) {
tokenizer.nextToken(); // advance tokenizer position
result.add(nextToken);
}
}
}
}
}
return result;
}
public static boolean canBeCompilerOptionValue(final String text) {
if (text.startsWith("-")) { // option or negative number
return text.length() > 1 && Character.isDigit(text.charAt(1));
}
return !text.startsWith("+");
}
public static String removeOptions(final String commandLine, final String... optionsToRemove) {
if (commandLine.isEmpty()) return commandLine;
final StringBuilder buf = new StringBuilder();
for (StringTokenizer tokenizer = new StringTokenizer(commandLine, " ", true); tokenizer.hasMoreTokens(); ) {
final String token = tokenizer.nextToken();
boolean remove = false;
for (String option : optionsToRemove) {
if (token.startsWith("-" + option)) {
remove = true;
break;
}
}
if (remove) {
String nextToken = null;
WHILE:
while (tokenizer.hasMoreElements()) {
nextToken = tokenizer.nextToken();
if (StringUtil.isEmptyOrSpaces(nextToken) || canBeCompilerOptionValue(nextToken)) {
continue;
}
for (String option : optionsToRemove) {
if (nextToken.startsWith("-" + option)) {
continue WHILE;
}
}
break;
}
if (nextToken != null && !canBeCompilerOptionValue(nextToken)) {
buf.append(nextToken);
}
}
else {
buf.append(token);
}
}
return buf.toString();
}
public static String getFlexCompilerWorkDirPath(final JpsProject project) {
final File dir = JpsModelSerializationDataService.getBaseDirectory(project);
return dir == null ? "" : dir.getPath();
}
@Nullable
public static String findXMLElement(final File file, final String xmlElement) {
try {
final BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(file));
try {
return findXMLElement(inputStream, xmlElement);
}
finally {
inputStream.close();
}
}
catch (IOException e) {
return null;
}
}
@Nullable
public static String findXMLElement(final InputStream is, final String xmlElement) {
// xmlElement has format "<root_tag><child_tag>"
final List<String> elementNames = StringUtil.split(StringUtil.replace(xmlElement, ">", ""), "<");
if (elementNames.isEmpty()) return null;
try {
final Element root = JDOMUtil.load(is);
if (!root.getName().equals(elementNames.get(0))) {
return null;
}
Element element = root;
int depth = 0;
while (elementNames.size() > ++depth) {
element = element.getChild(elementNames.get(depth), element.getNamespace());
if (element == null) {
return null;
}
}
return element.getTextNormalize();
}
catch (JDOMException | IOException ignore) {/**/}
return null;
}
public static String getMaximumTargetPlayer(final String sdkHome) {
return getMaximumVersion(getTargetPlayers(sdkHome));
}
@NotNull
public static String getMaximumVersion(final String[] versions) {
String version = versions.length > 0 ? versions[0] : "";
for (int i = 1; i < versions.length; i++) {
if (StringUtil.compareVersionNumbers(versions[i], version) > 0) {
version = versions[i];
}
}
return version;
}
public static String[] getTargetPlayers(final String sdkHome) {
final File playerFolder = new File(sdkHome + "/frameworks/libs/player");
if (playerFolder.isDirectory()) {
return playerFolder.list((dir, name) -> new File(playerFolder, name + "/playerglobal.swc").isFile());
}
return ArrayUtil.EMPTY_STRING_ARRAY;
}
/**
* @param processor (namespace, relative path with no leading slash)
*/
public static void processStandardNamespaces(final JpsFlexBuildConfiguration bc, final PairConsumer<String, String> processor) {
final JpsSdk<?> sdk = bc.getSdk();
if (bc.isPureAs() || sdk == null || sdk.getSdkType() != JpsFlexSdkType.INSTANCE) return;
if (StringUtil.compareVersionNumbers(sdk.getVersionString(), "4") < 0) {
processor.consume("http://www.adobe.com/2006/mxml", "frameworks/mxml-manifest.xml");
}
else {
processor.consume("http://ns.adobe.com/mxml/2009", "frameworks/mxml-2009-manifest.xml");
if (bc.getTargetPlatform() == TargetPlatform.Mobile ||
bc.getDependencies().getComponentSet() == ComponentSet.SparkAndMx ||
bc.getDependencies().getComponentSet() == ComponentSet.SparkOnly) {
processor.consume("library://ns.adobe.com/flex/spark", "frameworks/spark-manifest.xml");
}
if (bc.getTargetPlatform() != TargetPlatform.Mobile) {
if (bc.getDependencies().getComponentSet() == ComponentSet.SparkAndMx ||
bc.getDependencies().getComponentSet() == ComponentSet.MxOnly) {
processor.consume("library://ns.adobe.com/flex/mx", "frameworks/mx-manifest.xml");
}
processor.consume("http://www.adobe.com/2006/mxml", "frameworks/mxml-manifest.xml");
}
}
}
public static LinkageType getDefaultFrameworkLinkage(final String sdkVersion,
final BuildConfigurationNature nature) {
return nature.isLib()
? LinkageType.External
: nature.pureAS || !nature.isWebPlatform()
? LinkageType.Merged
: StringUtil.compareVersionNumbers(sdkVersion, "4") >= 0 && StringUtil.compareVersionNumbers(sdkVersion, "4.8") < 0
? LinkageType.RSL
: LinkageType.Merged; // Flex 3 or Apache Flex
}
/**
* If <code>LinkageType.Default</code> is returned then use {@link #getDefaultFrameworkLinkage(String, BuildConfigurationNature)} to get real value.
*
* @return <code>null</code> if entry should not be included at all
*/
@Nullable
public static LinkageType getSdkEntryLinkageType(final String swcPath, final JpsFlexBuildConfiguration bc) {
final JpsSdk<?> sdk = bc.getSdk();
LOG.assertTrue(sdk != null);
return getSdkEntryLinkageType(sdk.getHomePath(), swcPath, bc.getNature(), bc.getDependencies().getTargetPlayer(),
bc.getDependencies().getComponentSet());
}
/**
* If <code>LinkageType.Default</code> is returned then use {@link #getDefaultFrameworkLinkage(String, BuildConfigurationNature)} to get real value.
*
* @return <code>null</code> if entry should not be included at all
*/
@Nullable
public static LinkageType getSdkEntryLinkageType(final String sdkHome,
final String swcPath,
final BuildConfigurationNature bcNature,
final String targetPlayer,
final ComponentSet componentSet) {
LOG.assertTrue(!swcPath.endsWith("!/"), "plain local filesystem path is expected");
if (swcPath.endsWith("/frameworks/libs/air/airglobal.swc")) {
return bcNature.isWebPlatform() ? null : LinkageType.External;
}
if (swcPath.endsWith("/playerglobal.swc") && swcPath.contains("/frameworks/libs/player/")) {
if (swcPath.endsWith("/frameworks/libs/player/" + targetPlayer + "/playerglobal.swc")) {
return bcNature.isWebPlatform() ? LinkageType.External : null;
}
return null;
}
final boolean swcIncluded;
final int lastSlashIndex = swcPath.lastIndexOf('/');
if (lastSlashIndex <= 0 || lastSlashIndex == swcPath.length() - 1) {
LOG.error("Unexpected Flex SDK root: " + swcPath);
}
final String swcName = swcPath.substring(lastSlashIndex + 1).toLowerCase();
final String folderPath = swcPath.substring(0, lastSlashIndex);
if (folderPath.endsWith("/frameworks/libs")) {
swcIncluded = isSwcFromLibsFolderIncluded(bcNature, componentSet, swcName);
}
else if (folderPath.endsWith("/frameworks/libs/air")) {
swcIncluded = isSwcFromAirFolderIncluded(bcNature, componentSet, swcName);
}
else if (folderPath.endsWith("/frameworks/libs/mobile")) {
swcIncluded = isSwcFromMobileFolderIncluded(bcNature, swcName);
}
else if (folderPath.endsWith("/frameworks/libs/mx")) {
swcIncluded = isSwcFromMxFolderIncluded(bcNature, componentSet, swcName);
}
else if (folderPath.contains("/frameworks/themes/")) {
swcIncluded = false;
}
else {
if (Utils.IS_TEST_MODE) {
LOG.warn("Unknown Flex SDK root: " + swcPath);
}
swcIncluded = true;
}
if (!swcIncluded) return null;
// our difference from FB is that in case of library _ALL_ SWCs from SDK are external by default (except *global.swc)
if (bcNature.isLib()) return LinkageType.Default;
return RslUtil.canBeRsl(sdkHome, swcPath) ? LinkageType.Default : LinkageType.Merged;
}
private static boolean isSwcFromLibsFolderIncluded(final BuildConfigurationNature bcNature,
final ComponentSet componentSet,
final String swcName) {
if (swcName.equals("advancedgrids.swc")) {
return !(bcNature.isMobilePlatform() || bcNature.pureAS || componentSet == ComponentSet.SparkOnly);
}
if (swcName.equals("authoringsupport.swc")) {
return true;
}
if (swcName.equals("charts.swc")) {
return !bcNature.pureAS;
}
if (swcName.equals("core.swc")) {
return bcNature.pureAS;
}
if (swcName.equals("datavisualization.swc")) {
return !bcNature.pureAS;
}
if (swcName.endsWith("flash-integration.swc")) {
return !bcNature.pureAS;
}
if (swcName.equals("flex.swc")) {
return bcNature.pureAS;
}
if (swcName.endsWith("framework.swc")) {
return !bcNature.pureAS;
}
if (swcName.endsWith("osmf.swc")) {
return true;
}
if (swcName.endsWith("rpc.swc")) {
return !bcNature.pureAS;
}
if (swcName.endsWith("spark.swc")) {
return !bcNature.pureAS && (bcNature.isMobilePlatform() || componentSet != ComponentSet.MxOnly);
}
if (swcName.endsWith("spark_dmv.swc")) {
return !bcNature.pureAS && !bcNature.isMobilePlatform() && componentSet == ComponentSet.SparkAndMx;
}
if (swcName.endsWith("sparkskins.swc")) {
return !bcNature.pureAS && !bcNature.isMobilePlatform() && componentSet != ComponentSet.MxOnly;
}
if (swcName.endsWith("textlayout.swc")) {
return true;
}
if (swcName.endsWith("utilities.swc")) {
return true;
}
if (swcName.endsWith("asc-support.swc")) {
return true;
}
if (swcName.equals("apache.swc") ||
swcName.equals("experimental.swc")) {
return !bcNature.pureAS; // Apache Flex SDK 4.9
}
if (swcName.equals("experimental_mobile.swc")) {
return bcNature.isMobilePlatform() && !bcNature.pureAS; // Apache Flex SDK 4.11
}
if (swcName.equals("automation.swc") ||
swcName.equals("automation_agent.swc") ||
swcName.equals("automation_dmv.swc") ||
swcName.equals("automation_flashflexkit.swc") ||
swcName.equals("qtp.swc")) {
// additionally installed on top of Flex SDK 3.x
return true;
}
LOG.warn("Unknown SWC in '<Flex SDK>/frameworks/libs' folder: " + swcName);
return true;
}
private static boolean isSwcFromAirFolderIncluded(final BuildConfigurationNature bcNature,
final ComponentSet componentSet,
final String swcName) {
if (bcNature.isMobilePlatform()) {
return swcName.equals("servicemonitor.swc");
}
if (bcNature.isDesktopPlatform()) {
if (swcName.equals("airframework.swc")) {
return !bcNature.pureAS;
}
if (swcName.equals("airspark.swc")) {
return !bcNature.pureAS && componentSet != ComponentSet.MxOnly;
}
return true;
}
return false;
}
private static boolean isSwcFromMobileFolderIncluded(final BuildConfigurationNature bcNature, final String swcName) {
return bcNature.isMobilePlatform() && !bcNature.pureAS;
}
private static boolean isSwcFromMxFolderIncluded(final BuildConfigurationNature bcNature,
final ComponentSet componentSet,
final String swcName) {
if (!swcName.equals("mx.swc")) {
LOG.warn("Unknown SWC in '<Flex SDK>/frameworks/libs/mx' folder: " + swcName);
}
return !bcNature.isMobilePlatform() && !bcNature.pureAS && componentSet != ComponentSet.SparkOnly;
}
public static boolean checkDependencyType(final OutputType bcOutputType,
final OutputType dependencyBCOutputType,
final LinkageType linkageType) {
switch (dependencyBCOutputType) {
case Application:
case RuntimeLoadedModule:
return bcOutputType != OutputType.Library && linkageType == LinkageType.LoadInRuntime;
case Library:
return ArrayUtil.contains(linkageType, LinkageType.getSwcLinkageValues());
default:
LOG.error(dependencyBCOutputType);
return false;
}
}
public static String getPathToBundledJar(String filename) {
final URL url = FlexCommonUtils.class.getResource("");
if ("jar".equals(url.getProtocol())) {
// running from build
return FileUtil.toSystemDependentName(PathManager.getHomePath() + "/plugins/flex/lib/" + filename);
}
else {
final File dir1 = new File("../lib");
if (dir1.isDirectory()) {
final String path = FileUtil.toSystemIndependentName(FileUtil.toCanonicalPath(dir1.getAbsolutePath()));
if (path.endsWith("/flex/lib")) {
// running tests from 'flex-plugin' project
return FileUtil.toSystemDependentName(path + "/" + filename);
}
}
final File dir2 = new File(PathManager.getHomePath() + "/plugins/flex/lib");
if (dir2.isDirectory()) {
// running IDE from 'flex-plugin' project
return FileUtil.toSystemIndependentName(dir2.getAbsolutePath() + "/" + filename);
}
// running from 'IDEA' project sources
return FileUtil.toSystemDependentName(PathManager.getHomePath() + "/contrib/flex/lib/" + filename);
}
}
public static Collection<String> getFlexUnitSupportLibNames(final BuildConfigurationNature nature,
final ComponentSet componentSet,
final String pathToFlexUnitMainClass) {
boolean flexUnit4 = true;
try {
final String content = FileUtil.loadFile(new File(pathToFlexUnitMainClass), SDK_TOOLS_ENCODING);
if (content.contains(FLEXUNIT_1_TEST_RUNNER)) {
flexUnit4 = false;
}
}
catch (IOException ignore) {/*unlucky*/}
final Collection<String> result = new ArrayList<>(2);
if (flexUnit4) {
result.add("unittestingsupport_flexunit_4.swc");
}
if (nature.pureAS) {
result.add("unittestingsupport_as.swc");
}
else if (nature.isMobilePlatform() || componentSet == ComponentSet.SparkOnly) {
result.add("unittestingsupport_spark.swc");
}
else {
result.add("unittestingsupport_mx.swc");
}
return result;
}
public static String getPathToMainClassFile(final String mainClassFqn, final JpsModule module) {
if (StringUtil.isEmpty(mainClassFqn)) return "";
final String s = mainClassFqn.replace('.', '/');
final String[] classFileRelPaths = {"/" + s + ".mxml", "/" + s + ".as"};
for (JpsModuleSourceRoot srcRoot : module.getSourceRoots()) {
final String srcRootPath = JpsPathUtil.urlToPath(srcRoot.getUrl());
for (final String classFileRelPath : classFileRelPaths) {
final String pathToMainClassFile = srcRootPath + classFileRelPath;
if (new File(pathToMainClassFile).isFile()) {
return pathToMainClassFile;
}
}
}
return "";
}
public static String replacePathMacros(final @NotNull String text, final @NotNull JpsModule module, final @NotNull String sdkRootPath) {
String preResult = StringUtil.replace(text, CompilerOptionInfo.FLEX_SDK_MACRO, sdkRootPath);
final File moduleDir = JpsModelSerializationDataService.getBaseDirectory(module);
if (moduleDir != null) {
preResult = StringUtil.replace(preResult, "${MODULE_DIR}", moduleDir.getPath());
}
final File projectDir = JpsModelSerializationDataService.getBaseDirectory(module.getProject());
if (projectDir != null) {
preResult = StringUtil.replace(preResult, "${PROJECT_DIR}", projectDir.getPath());
}
preResult = StringUtil.replace(preResult, "${USER_HOME}", SystemProperties.getUserHome());
final StringBuilder builder = new StringBuilder(preResult);
int startIndex;
int endIndex = 0;
while ((startIndex = builder.indexOf("${", endIndex)) >= 0) {
endIndex = builder.indexOf("}", startIndex);
if (endIndex > startIndex) {
final String macroName = builder.substring(startIndex + 2, endIndex);
final String macroValue = JpsModelSerializationDataService.getPathVariableValue(module.getProject().getModel().getGlobal(),
macroName);
if (macroValue != null && !StringUtil.isEmptyOrSpaces(macroValue)) {
builder.replace(startIndex, endIndex + 1, macroValue);
endIndex = endIndex + macroValue.length() - (macroName.length() + 3);
}
}
else {
break;
}
}
return builder.toString();
}
public static String getFlexUnitLauncherExtension(final BuildConfigurationNature nature) {
return nature.pureAS ? ".as" : ".mxml";
}
public static boolean is64BitJava6(final String javaHome) {
JdkVersionDetector.JdkVersionInfo info = JdkVersionDetector.getInstance().detectJdkVersionInfo(javaHome);
if (info != null) {
boolean is64Bit = info.getBitness() == Bitness.x64;
boolean isJava6 = info.getVersion().contains("version \"1.6.");
return is64Bit && isJava6;
}
return false;
}
public static List<String> getCommandLineForSdkTool(final @NotNull JpsProject project,
final @NotNull JpsSdk<?> sdk,
final @Nullable String additionalClasspath,
final @NotNull String mainClass) {
String javaHome = SystemProperties.getJavaHome();
boolean customJavaHomeSet = false;
String additionalJavaArgs = null;
int heapSizeMbFromJvmConfig = 0;
String classpath = additionalClasspath;
final boolean isFlexmojos = sdk.getSdkType() == JpsFlexmojosSdkType.INSTANCE;
final JpsFlexmojosSdkProperties flexmojosSdkData = isFlexmojos
? ((JpsSimpleElement<JpsFlexmojosSdkProperties>)sdk.getSdkProperties()).getData()
: null;
if (isFlexmojos) {
classpath = (StringUtil.isEmpty(classpath) ? "" : (classpath + File.pathSeparator)) +
FileUtil.toSystemDependentName(StringUtil.join(flexmojosSdkData.getFlexCompilerClasspath(), File.pathSeparator));
}
else {
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream(FileUtil.toSystemDependentName(sdk.getHomePath() + "/bin/jvm.config"));
final Properties properties = new Properties();
properties.load(inputStream);
final String configuredJavaHome = properties.getProperty("java.home");
if (configuredJavaHome != null && configuredJavaHome.trim().length() > 0) {
javaHome = configuredJavaHome;
customJavaHomeSet = true;
}
final String javaArgs = properties.getProperty("java.args");
if (javaArgs != null && javaArgs.trim().length() > 0) {
additionalJavaArgs = javaArgs;
final Matcher matcher = XMX_PATTERN.matcher(javaArgs);
if (matcher.matches()) {
try {
heapSizeMbFromJvmConfig = Integer.parseInt(matcher.group(2));
}
catch (NumberFormatException e) {/*ignore*/}
}
}
final String classpathFromJvmConfig = properties.getProperty("java.class.path");
if (classpathFromJvmConfig != null && classpathFromJvmConfig.trim().length() > 0) {
classpath = (StringUtil.isEmpty(classpath) ? "" : (classpath + File.pathSeparator)) + classpathFromJvmConfig;
}
//jvm.config also has properties which are not handled here: 'env' and 'java.library.path'; though not sure that there's any sense in them
}
catch (IOException e) {
// not a big problem, will use default settings
if (inputStream != null) {
try {
inputStream.close();
}
catch (IOException e1) {/*ignore*/}
}
}
}
final String javaExecutable = FileUtil.toSystemDependentName((javaHome + "/bin/java" + (SystemInfo.isWindows ? ".exe" : "")));
final String applicationHomeParam =
isFlexmojos ? null : ("-Dapplication.home=" + FileUtil.toSystemDependentName(sdk.getHomePath()));
final String d32 = getD32IfNeed(customJavaHomeSet, javaHome);
final List<String> result = new ArrayList<>();
result.add(javaExecutable);
if (StringUtil.isNotEmpty(d32)) result.add(d32);
if (StringUtil.isNotEmpty(applicationHomeParam)) result.add(applicationHomeParam);
if (StringUtil.isNotEmpty(additionalJavaArgs)) result.addAll(StringUtil.split(additionalJavaArgs, " "));
final String vmOptions = JpsFlexCompilerProjectExtension.getInstance(project).VM_OPTIONS;
if (StringUtil.isNotEmpty(vmOptions)) result.addAll(StringUtil.split(vmOptions, " "));
if (additionalJavaArgs == null || !additionalJavaArgs.contains("file.encoding")) {
result.add("-Dfile.encoding=" + SDK_TOOLS_ENCODING);
}
result.add("-Djava.awt.headless=true");
result.add("-Duser.language=en");
result.add("-Duser.region=en");
final int heapSizeMb = JpsFlexCompilerProjectExtension.getInstance(project).HEAP_SIZE_MB;
if (heapSizeMb > heapSizeMbFromJvmConfig) {
result.add("-Xmx" + heapSizeMb + "m");
}
if (StringUtil.isNotEmpty(classpath)) {
result.add("-classpath");
result.add(classpath);
}
result.add(mainClass);
return result;
}
public static String getD32IfNeed(boolean customJavaHomeSet, String javaHome) {
return (!customJavaHomeSet && SystemInfo.isMac && is64BitJava6(javaHome)) ? "-d32" : null;
}
@Nullable
public static String getPathRelativeToSourceRoot(final JpsModule module, final String _path) {
final String path = FileUtil.toSystemIndependentName(_path);
for (JpsModuleSourceRoot srcRoot : module.getSourceRoots()) {
final String rootPath = JpsPathUtil.urlToPath(srcRoot.getUrl());
if (path.equals(rootPath)) return "";
if (path.startsWith(rootPath + "/")) return path.substring(rootPath.length() + 1);
}
return null;
}
@Nullable
public static String getPathRelativeToContentRoot(final JpsModule module, final String path) {
for (String rootUrl : module.getContentRootsList().getUrls()) {
final String rootPath = JpsPathUtil.urlToPath(rootUrl);
if (path.equals(rootPath)) return "";
if (path.startsWith(rootPath + "/")) return path.substring(rootPath.length() + 1);
}
return null;
}
public static String getWrapperFileName(final JpsFlexBuildConfiguration bc) {
return FileUtil.getNameWithoutExtension(PathUtilRt.getFileName(bc.getActualOutputFilePath())) + ".html";
}
public static String getGeneratedAirDescriptorName(final JpsFlexBuildConfiguration bc, final JpsAirPackagingOptions packagingOptions) {
final String suffix = packagingOptions instanceof JpsAirDesktopPackagingOptions
? "-descriptor.xml"
: packagingOptions instanceof JpsAndroidPackagingOptions ? "-android-descriptor.xml"
: "-ios-descriptor.xml";
return FileUtil.getNameWithoutExtension(PathUtilRt.getFileName(bc.getActualOutputFilePath())) + suffix;
}
public static String replace(final String text, final Map<String, String> replacementMap) {
final String[] from = new String[replacementMap.size()];
final String[] to = new String[replacementMap.size()];
int i = 0;
for (Map.Entry<String, String> entry : replacementMap.entrySet()) {
from[i] = entry.getKey();
to[i] = entry.getValue();
i++;
}
return StringUtil.replace(text, from, to);
}
@Nullable
public static String getVersionOfAirSdkIncludedInFlexSdk(final String flexSdkHomePath) {
final File adtFile = new File(flexSdkHomePath + "/lib/adt.jar");
if (!adtFile.isFile()) {
return null;
}
String version = ourAdtJarPathAndTimestampToVersion.get(Pair.create(adtFile.getPath(), adtFile.lastModified()));
if (version != null) {
return version;
}
try {
final Ref<String> versionRef = Ref.create();
final String javaExecutable =
FileUtil.toSystemDependentName((SystemProperties.getJavaHome() + "/bin/java" + (SystemInfo.isWindows ? ".exe" : "")));
String[] cmdarray = {javaExecutable, "-jar", adtFile.getPath(), "-version"};
final Process process = Runtime.getRuntime().exec(cmdarray);
final BaseOSProcessHandler handler = new BaseOSProcessHandler(process, StringUtil.join(cmdarray, " "), Charset.defaultCharset());
handler.addProcessListener(new ProcessAdapter() {
public void onTextAvailable(ProcessEvent event, Key outputType) {
if (outputType != ProcessOutputTypes.SYSTEM) {
parseAirVersionFromAdtOutput(event.getText().trim(), versionRef);
}
}
});
handler.startNotify();
handler.waitFor(3000);
if (!handler.isProcessTerminated()) {
handler.destroyProcess();
}
version = versionRef.get();
ourAdtJarPathAndTimestampToVersion.put(Pair.create(adtFile.getPath(), adtFile.lastModified()), version);
return version;
}
catch (IOException e) {/*ignore*/}
return null;
}
public static void parseAirVersionFromAdtOutput(String adtOutput, final Ref<String> versionRef) {
// adt version "1.5.0.7220"
// 13.0.0.36
final String prefix = "adt version \"";
final String suffix = "\"";
if (adtOutput.startsWith(prefix) && adtOutput.endsWith(suffix)) {
adtOutput = adtOutput.substring(prefix.length(), adtOutput.length() - suffix.length());
}
if (AIR_VERSION_PATTERN.matcher(adtOutput).matches()) {
versionRef.set(adtOutput);
}
}
@Nullable
public static String getAirVersion(final String sdkHomePath, final String sdkVersion) {
final String version;
if (sdkVersion != null && sdkVersion.startsWith(AIR_SDK_VERSION_PREFIX)) {
version = sdkVersion.substring(AIR_SDK_VERSION_PREFIX.length());
}
else if (sdkHomePath != null && sdkHomePath.endsWith(".pom") && new File(sdkHomePath).isFile()) {
version = guessAirSdkVersionByFlexmojosSdkVersion(sdkVersion);
}
else {
version = getVersionOfAirSdkIncludedInFlexSdk(sdkHomePath);
}
if (version != null) {
final Trinity<String, String, String> majorMinorRevision = getMajorMinorRevisionVersion(version);
return majorMinorRevision.third.isEmpty() || "0".equals(majorMinorRevision.third)
? majorMinorRevision.first + "." + majorMinorRevision.second
: majorMinorRevision.first + "." + majorMinorRevision.second + "." + majorMinorRevision.third;
}
return null;
}
private static String guessAirSdkVersionByFlexmojosSdkVersion(final String sdkVersion) {
// todo consider separate Flex and AIR SDK management supported by Flexmojos 6.
if (StringUtil.compareVersionNumbers(sdkVersion, "4") < 0) {
if (StringUtil.compareVersionNumbers(sdkVersion, "3.1") < 0) return "1.0";
if (StringUtil.compareVersionNumbers(sdkVersion, "3.2") < 0) return "1.1";
if (StringUtil.compareVersionNumbers(sdkVersion, "3.3") < 0) return "1.5";
if (StringUtil.compareVersionNumbers(sdkVersion, "3.4") < 0) return "1.5";
if (StringUtil.compareVersionNumbers(sdkVersion, "3.5") < 0) return "1.5.2";
return "1.5.3";
}
if (StringUtil.compareVersionNumbers(sdkVersion, "4.1") < 0) return "1.5.3";
if (StringUtil.compareVersionNumbers(sdkVersion, "4.5") < 0) return "2.0";
if (StringUtil.compareVersionNumbers(sdkVersion, "4.6") < 0) return "2.6";
return "3.1";
}
public static String fixApplicationId(final String appId) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < appId.length(); i++) {
final char ch = appId.charAt(i);
if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9' || ch == '-' || ch == '.') {
builder.append(ch);
}
}
return builder.toString();
}
@Nullable
public static String parseAirVersionFromDescriptorFile(final String descriptorFilePath) {
if (StringUtil.isEmpty(descriptorFilePath)) return null;
try {
final Element rootElement = JDOMUtil.load(new File(descriptorFilePath));
final String localName = rootElement.getName();
final Namespace namespace = rootElement.getNamespace();
if ("application".equals(localName) && namespace != null && namespace.getURI().startsWith(AIR_NAMESPACE_BASE)) {
return namespace.getURI().substring(AIR_NAMESPACE_BASE.length());
}
}
catch (JDOMException | IOException e) {/*unlucky*/}
return null;
}
public static String getSwfVersionForTargetPlayer(final String targetPlayer) {
if (StringUtil.compareVersionNumbers(targetPlayer, "30") >= 0) return "41";
if (StringUtil.compareVersionNumbers(targetPlayer, "29") >= 0) return "40";
if (StringUtil.compareVersionNumbers(targetPlayer, "28") >= 0) return "39";
if (StringUtil.compareVersionNumbers(targetPlayer, "27") >= 0) return "38";
if (StringUtil.compareVersionNumbers(targetPlayer, "26") >= 0) return "37";
if (StringUtil.compareVersionNumbers(targetPlayer, "25") >= 0) return "36";
if (StringUtil.compareVersionNumbers(targetPlayer, "24") >= 0) return "35";
if (StringUtil.compareVersionNumbers(targetPlayer, "23") >= 0) return "34";
if (StringUtil.compareVersionNumbers(targetPlayer, "22") >= 0) return "33";
if (StringUtil.compareVersionNumbers(targetPlayer, "21") >= 0) return "32";
if (StringUtil.compareVersionNumbers(targetPlayer, "20") >= 0) return "31";
if (StringUtil.compareVersionNumbers(targetPlayer, "19") >= 0) return "30";
if (StringUtil.compareVersionNumbers(targetPlayer, "18") >= 0) return "29";
if (StringUtil.compareVersionNumbers(targetPlayer, "17") >= 0) return "28";
if (StringUtil.compareVersionNumbers(targetPlayer, "16") >= 0) return "27";
if (StringUtil.compareVersionNumbers(targetPlayer, "15") >= 0) return "26";
if (StringUtil.compareVersionNumbers(targetPlayer, "14") >= 0) return "25";
if (StringUtil.compareVersionNumbers(targetPlayer, "13") >= 0) return "24";
if (StringUtil.compareVersionNumbers(targetPlayer, "12") >= 0) return "23";
if (StringUtil.compareVersionNumbers(targetPlayer, "11.9") >= 0) return "22";
if (StringUtil.compareVersionNumbers(targetPlayer, "11.8") >= 0) return "21";
if (StringUtil.compareVersionNumbers(targetPlayer, "11.7") >= 0) return "20";
if (StringUtil.compareVersionNumbers(targetPlayer, "11.6") >= 0) return "19";
if (StringUtil.compareVersionNumbers(targetPlayer, "11.5") >= 0) return "18";
if (StringUtil.compareVersionNumbers(targetPlayer, "11.4") >= 0) return "17";
if (StringUtil.compareVersionNumbers(targetPlayer, "11.3") >= 0) return "16";
if (StringUtil.compareVersionNumbers(targetPlayer, "11.2") >= 0) return "15";
if (StringUtil.compareVersionNumbers(targetPlayer, "11.1") >= 0) return "14";
if (StringUtil.compareVersionNumbers(targetPlayer, "11") >= 0) return "13";
if (StringUtil.compareVersionNumbers(targetPlayer, "10.3") >= 0) return "12";
if (StringUtil.compareVersionNumbers(targetPlayer, "10.2") >= 0) return "11";
if (StringUtil.compareVersionNumbers(targetPlayer, "10.1") >= 0) return "10";
return "9";
}
public static String getSwfVersionForAirVersion(final String airVersion) {
if (StringUtil.compareVersionNumbers(airVersion, "30") >= 0) return "41";
if (StringUtil.compareVersionNumbers(airVersion, "29") >= 0) return "40";
if (StringUtil.compareVersionNumbers(airVersion, "28") >= 0) return "39";
if (StringUtil.compareVersionNumbers(airVersion, "27") >= 0) return "38";
if (StringUtil.compareVersionNumbers(airVersion, "26") >= 0) return "37";
if (StringUtil.compareVersionNumbers(airVersion, "25") >= 0) return "36";
if (StringUtil.compareVersionNumbers(airVersion, "24") >= 0) return "35";
if (StringUtil.compareVersionNumbers(airVersion, "23") >= 0) return "34";
if (StringUtil.compareVersionNumbers(airVersion, "22") >= 0) return "33";
if (StringUtil.compareVersionNumbers(airVersion, "21") >= 0) return "32";
if (StringUtil.compareVersionNumbers(airVersion, "20") >= 0) return "31";
if (StringUtil.compareVersionNumbers(airVersion, "19") >= 0) return "30";
if (StringUtil.compareVersionNumbers(airVersion, "18") >= 0) return "29";
if (StringUtil.compareVersionNumbers(airVersion, "17") >= 0) return "28";
if (StringUtil.compareVersionNumbers(airVersion, "16") >= 0) return "27";
if (StringUtil.compareVersionNumbers(airVersion, "15") >= 0) return "26";
if (StringUtil.compareVersionNumbers(airVersion, "14") >= 0) return "25";
if (StringUtil.compareVersionNumbers(airVersion, "13") >= 0) return "24"; // yes, they are going to release 13 after 4
if (StringUtil.compareVersionNumbers(airVersion, "4") >= 0) return "23";
if (StringUtil.compareVersionNumbers(airVersion, "3.9") >= 0) return "22";
if (StringUtil.compareVersionNumbers(airVersion, "3.8") >= 0) return "21";
if (StringUtil.compareVersionNumbers(airVersion, "3.7") >= 0) return "20";
if (StringUtil.compareVersionNumbers(airVersion, "3.6") >= 0) return "19";
if (StringUtil.compareVersionNumbers(airVersion, "3.5") >= 0) return "18";
if (StringUtil.compareVersionNumbers(airVersion, "3.4") >= 0) return "17";
if (StringUtil.compareVersionNumbers(airVersion, "3.3") >= 0) return "16";
if (StringUtil.compareVersionNumbers(airVersion, "3.2") >= 0) return "15";
if (StringUtil.compareVersionNumbers(airVersion, "3.1") >= 0) return "14";
if (StringUtil.compareVersionNumbers(airVersion, "3") >= 0) return "13";
if (StringUtil.compareVersionNumbers(airVersion, "2.7") >= 0) return "12";
if (StringUtil.compareVersionNumbers(airVersion, "2.6") >= 0) return "11";
if (StringUtil.compareVersionNumbers(airVersion, "1.5") >= 0) return "10";
return "9";
}
/**
* Try not to use this method. Correct swf version can be obtained only by target player or AIR version.
*/
public static String getSwfVersionForSdk_THE_WORST_WAY(final String sdkVersion) {
if (sdkVersion.startsWith(AIR_SDK_VERSION_PREFIX)) {
return getSwfVersionForAirVersion(sdkVersion.substring(AIR_SDK_VERSION_PREFIX.length()));
}
if (StringUtil.compareVersionNumbers(sdkVersion, "4.6") >= 0) return "14";
if (StringUtil.compareVersionNumbers(sdkVersion, "4.5") >= 0) return "11";
assert false : sdkVersion;
return null;
}
public static boolean containsASC20(final String sdkHome) {
return new File(sdkHome + "/lib/compiler.jar").isFile();
}
public static Pair<String, Integer> getSourcePathAndLineFromASC20Message(final String message) {
if (message == null) return null;
final int index = message.lastIndexOf(':');
if (index <= 0) return null;
final String filePath = message.substring(0, index);
final String lineNumber = message.substring(index + 1);
try {
final int line = Integer.parseInt(lineNumber);
if (new File(filePath).isFile()) {
return Pair.create(FileUtil.toSystemIndependentName(filePath), line);
}
}
catch (NumberFormatException e) {/*unlucky*/}
return null;
}
public static InputStreamReader createInputStreamReader(final InputStream inputStream) {
try {
return new InputStreamReader(inputStream, SDK_TOOLS_ENCODING);
}
catch (UnsupportedEncodingException e) {
return new InputStreamReader(inputStream);
}
}
public static String fixSizeReportOption(final String additionalOptions, final String postfix) {
final List<String> values = getOptionValues(additionalOptions, "size-report");
final StringBuilder result = new StringBuilder(removeOptions(additionalOptions, "size-report"));
if (values.size() == 1 && values.get(0).toLowerCase().endsWith(".xml")) {
final String path = values.get(0);
result.append(" -size-report=");
if (path.contains(" ")) {
result.append("\"");
}
result.append(path.substring(0, path.length() - ".xml".length()));
result.append("-").append(postfix);
result.append(path.substring(path.length() - ".xml".length()));
if (path.contains(" ")) {
result.append("\"");
}
}
return result.toString();
}
public static boolean isAirSdkWithoutFlex(final @Nullable JpsSdk<?> sdk) {
final String version = sdk == null ? null : sdk.getVersionString();
return version != null && version.startsWith(AIR_SDK_VERSION_PREFIX);
}
public static Trinity<String, String, String> getMajorMinorRevisionVersion(final @NotNull String version) {
final int firstDotIndex = version.indexOf('.');
if (firstDotIndex == -1) {
return Trinity.create(version, "0", "0");
}
final String majorVersion = version.substring(0, firstDotIndex);
final int secondDotIndex = version.indexOf('.', firstDotIndex + 1);
if (secondDotIndex == -1) {
return Trinity.create(majorVersion, version.substring(firstDotIndex + 1), "0");
}
final String minorVersion = version.substring(firstDotIndex + 1, secondDotIndex);
final int thirdDotIndex = version.indexOf('.', secondDotIndex + 1);
final String revision = thirdDotIndex == -1 ? version.substring(secondDotIndex + 1)
: version.substring(secondDotIndex + 1, thirdDotIndex);
return Trinity.create(majorVersion, minorVersion, revision);
}
public static void deleteTempFlexConfigFiles(final String projectName) {
if (KEEP_TEMP_FILES) return;
final String hash1 = Integer.toHexString((SystemProperties.getUserName() + projectName).hashCode()).toUpperCase();
final File dir = new File(getTempFlexConfigsDirPath());
if (!dir.isDirectory()) return;
final File[] filesToDelete = dir.listFiles((file, name) -> {
return name.startsWith("idea-" + hash1) && name.endsWith(".xml"); // PlatformUtils.getPlatformPrefix().toLowerCase()
});
if (filesToDelete != null) {
for (final File file : filesToDelete) {
FileUtil.delete(file);
}
}
}
}