001 /*
002 * Copyright 2010-2013 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.k2js.config;
018
019 import com.google.common.collect.Lists;
020 import com.intellij.openapi.diagnostic.Logger;
021 import com.intellij.openapi.project.Project;
022 import com.intellij.openapi.util.Key;
023 import com.intellij.openapi.util.io.FileUtil;
024 import com.intellij.openapi.util.text.StringUtil;
025 import com.intellij.openapi.vfs.*;
026 import com.intellij.psi.PsiFile;
027 import com.intellij.psi.PsiManager;
028 import org.jetbrains.annotations.NotNull;
029 import org.jetbrains.jet.lang.psi.JetFile;
030
031 import java.io.File;
032 import java.io.IOException;
033 import java.io.InputStream;
034 import java.util.ArrayList;
035 import java.util.Collections;
036 import java.util.Enumeration;
037 import java.util.List;
038 import java.util.zip.ZipEntry;
039 import java.util.zip.ZipFile;
040
041 import static org.jetbrains.jet.lang.psi.PsiPackage.JetPsiFactory;
042 import static org.jetbrains.jet.utils.LibraryUtils.isJsRuntimeLibrary;
043
044 public class LibrarySourcesConfig extends Config {
045 @NotNull
046 public static final Key<String> EXTERNAL_MODULE_NAME = Key.create("externalModule");
047 @NotNull
048 public static final String UNKNOWN_EXTERNAL_MODULE_NAME = "<unknown>";
049
050 @NotNull
051 private static final Logger LOG = Logger.getInstance("#org.jetbrains.k2js.config.LibrarySourcesConfig");
052 public static final String STDLIB_JS_MODULE_NAME = "stdlib";
053 public static final String STDLIB_JS_FILE_NAME = STDLIB_JS_MODULE_NAME + ".js";
054
055 @NotNull
056 private final List<String> files;
057
058 public LibrarySourcesConfig(
059 @NotNull Project project,
060 @NotNull String moduleId,
061 @NotNull List<String> files,
062 @NotNull EcmaVersion ecmaVersion,
063 boolean sourcemap,
064 boolean inlineEnabled
065 ) {
066 super(project, moduleId, ecmaVersion, sourcemap, inlineEnabled);
067 this.files = files;
068 }
069
070 @NotNull
071 @Override
072 protected List<JetFile> generateLibFiles() {
073 if (files.isEmpty()) {
074 return Collections.emptyList();
075 }
076
077 List<JetFile> jetFiles = new ArrayList<JetFile>();
078 String moduleName = UNKNOWN_EXTERNAL_MODULE_NAME;
079 VirtualFileSystem fileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL);
080 PsiManager psiManager = PsiManager.getInstance(getProject());
081
082 for (String path : files) {
083 if (path.charAt(0) == '@') {
084 moduleName = path.substring(1);
085 }
086 else if (path.endsWith(".jar") || path.endsWith(".zip")) {
087 String actualModuleName = isJsRuntimeLibrary(new File(path)) ? STDLIB_JS_MODULE_NAME : moduleName;
088
089 try {
090 jetFiles.addAll(readZip(path, actualModuleName));
091 }
092 catch (IOException e) {
093 LOG.error(e);
094 }
095 }
096 else {
097 VirtualFile file = fileSystem.findFileByPath(path);
098 if (file == null) {
099 LOG.error("File '" + path + "not found.'");
100 }
101 else if (file.isDirectory()) {
102 JetFileCollector jetFileCollector = new JetFileCollector(jetFiles, moduleName, psiManager);
103 VfsUtilCore.visitChildrenRecursively(file, jetFileCollector);
104 }
105 else {
106 jetFiles.add(getJetFileByVirtualFile(file, moduleName, psiManager));
107 }
108 }
109 }
110
111 return jetFiles;
112 }
113
114 private List<JetFile> readZip(String file, String moduleName) throws IOException {
115 ZipFile zipFile = new ZipFile(file);
116 try {
117 return traverseArchive(zipFile, moduleName);
118 }
119 finally {
120 zipFile.close();
121 }
122 }
123
124 @NotNull
125 private List<JetFile> traverseArchive(@NotNull ZipFile zipFile, String moduleName) throws IOException {
126 List<JetFile> result = Lists.newArrayList();
127 Enumeration<? extends ZipEntry> zipEntries = zipFile.entries();
128 while (zipEntries.hasMoreElements()) {
129 ZipEntry entry = zipEntries.nextElement();
130 if (!entry.isDirectory() && entry.getName().endsWith(".kt")) {
131 InputStream stream = zipFile.getInputStream(entry);
132 String text = StringUtil.convertLineSeparators(FileUtil.loadTextAndClose(stream));
133 JetFile jetFile = JetPsiFactory(getProject()).createFile(entry.getName(), text);
134 jetFile.putUserData(EXTERNAL_MODULE_NAME, moduleName);
135 result.add(jetFile);
136 }
137 }
138 return result;
139 }
140
141 private static JetFile getJetFileByVirtualFile(VirtualFile file, String moduleName, PsiManager psiManager) {
142 PsiFile psiFile = psiManager.findFile(file);
143 assert psiFile != null;
144 psiFile.putUserData(EXTERNAL_MODULE_NAME, moduleName);
145 return (JetFile) psiFile;
146 }
147
148 private static class JetFileCollector extends VirtualFileVisitor {
149 private final List<JetFile> jetFiles;
150 private final String moduleName;
151 private final PsiManager psiManager;
152
153 private JetFileCollector(List<JetFile> files, String name, PsiManager manager) {
154 moduleName = name;
155 psiManager = manager;
156 jetFiles = files;
157 }
158
159 @Override
160 public boolean visitFile(@NotNull VirtualFile file) {
161 if (file.getName().endsWith(".kt")) {
162 jetFiles.add(getJetFileByVirtualFile(file, moduleName, psiManager));
163 return false;
164 }
165 return true;
166 }
167 }
168 }