package com.intellij.lang.javascript.flex.build; import com.intellij.lang.javascript.flex.FlexUtils; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.PathUtil; import com.intellij.util.text.CharSequenceReader; import com.intellij.util.xml.NanoXmlUtil; import org.jetbrains.annotations.NotNull; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.*; public class FlexCompilerConfigFileUtil { private static final Key<Pair<Long, Collection<NamespacesInfo>>> MOD_STAMP_TO_NAMESPACES_INFOS = Key.create("MOD_STAMP_TO_NAMESPACES_INFOS"); private static final Key<Pair<Long, InfoFromConfigFile>> MOD_STAMP_AND_INFO_FROM_CONFIG_FILE = Key.create("MOD_STAMP_AND_INFO_FROM_CONFIG_FILE"); private static final String TARGET_PLAYER_ELEMENT = "<flex-config><target-player>"; private static final String FILE_SPEC_ELEMENT = "<flex-config><file-specs><path-element>"; private static final String OUTPUT_ELEMENT = "<flex-config><output>"; public static final String INCLUDE_NAMESPACES = "include-namespaces"; public static final String NAMESPACES = "namespaces"; public static final String NAMESPACE = "namespace"; public static final String MANIFEST = "manifest"; public static final String URI = "uri"; public static final String DEFINE = "define"; public static final String NAME = "name"; public static final String VALUE = "value"; public static final String FILE_SPECS = "file-specs"; public static final String OUTPUT = "output"; public static class NamespacesInfo { public final String namespace; public final String manifest; public final boolean includedInSwc; private NamespacesInfo(final String namespace, final String manifest, final boolean includedInSwc) { this.namespace = namespace; this.manifest = manifest; this.includedInSwc = includedInSwc; } } private FlexCompilerConfigFileUtil() { } public static Collection<NamespacesInfo> getNamespacesInfos(final VirtualFile configFile) { if (configFile == null || !configFile.isValid() || configFile.isDirectory()) { return Collections.emptyList(); } Pair<Long, Collection<NamespacesInfo>> data = configFile.getUserData(MOD_STAMP_TO_NAMESPACES_INFOS); final FileDocumentManager documentManager = FileDocumentManager.getInstance(); final Document cachedDocument = documentManager.getCachedDocument(configFile); final Long currentTimestamp = cachedDocument != null ? cachedDocument.getModificationStamp() : configFile.getModificationCount(); final Long cachedTimestamp = data == null ? null : data.first; if (cachedTimestamp == null || !cachedTimestamp.equals(currentTimestamp)) { data = null; configFile.putUserData(MOD_STAMP_TO_NAMESPACES_INFOS, data); try { final NamespacesXmlBuilder builder = new NamespacesXmlBuilder(); if (cachedDocument != null) { //noinspection IOResourceOpenedButNotSafelyClosed NanoXmlUtil.parse(new CharSequenceReader(cachedDocument.getCharsSequence()), builder); } else { NanoXmlUtil.parse(configFile.getInputStream(), builder); } final Collection<NamespacesInfo> namespacesInfos = new ArrayList<>(); final Collection<String> includedInSwcNamespaces = builder.getIncludedNamespaces(); for (Pair<String, String> namespaceAndManifest : builder.getNamespacesAndManifests()) { namespacesInfos.add(new NamespacesInfo(namespaceAndManifest.first, namespaceAndManifest.second, includedInSwcNamespaces.contains(namespaceAndManifest.first))); } data = Pair.create(currentTimestamp, namespacesInfos); configFile.putUserData(MOD_STAMP_TO_NAMESPACES_INFOS, data); } catch (IOException ignored) { } } return data == null ? Collections.emptyList() : data.second; } @NotNull public static InfoFromConfigFile getInfoFromConfigFile(final String configFilePath) { final VirtualFile configFile = configFilePath.isEmpty() ? null : LocalFileSystem.getInstance().findFileByPath(configFilePath); if (configFile == null) { return InfoFromConfigFile.DEFAULT; } Pair<Long, InfoFromConfigFile> data = configFile.getUserData(MOD_STAMP_AND_INFO_FROM_CONFIG_FILE); final FileDocumentManager documentManager = FileDocumentManager.getInstance(); final Document cachedDocument = documentManager.getCachedDocument(configFile); final Long currentTimestamp = cachedDocument != null ? cachedDocument.getModificationStamp() : configFile.getModificationCount(); final Long cachedTimestamp = data == null ? null : data.first; if (cachedTimestamp == null || !cachedTimestamp.equals(currentTimestamp)) { data = null; configFile.putUserData(MOD_STAMP_AND_INFO_FROM_CONFIG_FILE, data); final List<String> xmlElements = Arrays.asList(FILE_SPEC_ELEMENT, OUTPUT_ELEMENT, TARGET_PLAYER_ELEMENT); String mainClassPath = null; String outputPath = null; String targetPlayer = null; try { final InputStream inputStream = cachedDocument == null ? configFile.getInputStream() : new ByteArrayInputStream(cachedDocument.getText().getBytes()); final Map<String, List<String>> map = FlexUtils.findXMLElements(inputStream, xmlElements); final List<String> fileSpecList = map.get(FILE_SPEC_ELEMENT); if (!fileSpecList.isEmpty()) { mainClassPath = fileSpecList.get(0).trim(); } final List<String> outputList = map.get(OUTPUT_ELEMENT); if (!outputList.isEmpty()) { outputPath = outputList.get(0).trim(); if (!FileUtil.isAbsolute(outputPath)) { try { outputPath = FileUtil.toSystemIndependentName(new File(configFile.getParent().getPath() + "/" + outputPath).getCanonicalPath()); } catch (IOException e) { outputPath = FileUtil.toSystemIndependentName(new File(configFile.getParent().getPath() + "/" + outputPath).getAbsolutePath()); } } } final List<String> targetPlayerList = map.get(TARGET_PLAYER_ELEMENT); if (!targetPlayerList.isEmpty()) { targetPlayer = targetPlayerList.get(0).trim(); } } catch (IOException ignore) {/*ignore*/ } final String outputFileName = outputPath == null ? null : PathUtil.getFileName(outputPath); final String outputFolderPath = outputPath == null ? null : PathUtil.getParentPath(outputPath); data = Pair.create(currentTimestamp, new InfoFromConfigFile(configFile, mainClassPath, outputFileName, outputFolderPath, targetPlayer)); configFile.putUserData(MOD_STAMP_AND_INFO_FROM_CONFIG_FILE, data); } return data.second; } }