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
017package org.jetbrains.k2js.config;
018
019import com.google.common.collect.Lists;
020import com.intellij.openapi.diagnostic.Logger;
021import com.intellij.openapi.project.Project;
022import com.intellij.openapi.util.Key;
023import com.intellij.openapi.util.io.FileUtil;
024import org.jetbrains.annotations.NotNull;
025import org.jetbrains.jet.lang.psi.JetFile;
026import org.jetbrains.k2js.utils.JetFileUtils;
027
028import java.io.File;
029import java.io.IOException;
030import java.io.InputStream;
031import java.util.ArrayList;
032import java.util.Collections;
033import java.util.Enumeration;
034import java.util.List;
035import java.util.zip.ZipEntry;
036import java.util.zip.ZipFile;
037
038public class LibrarySourcesConfig extends Config {
039    @NotNull
040    public static final Key<String> EXTERNAL_MODULE_NAME = new Key<String>("externalModule");
041    @NotNull
042    public static final String UNKNOWN_EXTERNAL_MODULE_NAME = "<unknown>";
043
044    @NotNull
045    private static final Logger LOG = Logger.getInstance("#org.jetbrains.k2js.config.LibrarySourcesConfig");
046
047    @NotNull
048    private final List<String> files;
049
050    public LibrarySourcesConfig(@NotNull Project project,
051            @NotNull String moduleId,
052            @NotNull List<String> files,
053            @NotNull EcmaVersion ecmaVersion) {
054        super(project, moduleId, ecmaVersion);
055        this.files = files;
056    }
057
058    @NotNull
059    @Override
060    public List<JetFile> generateLibFiles() {
061        if (files.isEmpty()) {
062            return Collections.emptyList();
063        }
064
065        List<JetFile> jetFiles = new ArrayList<JetFile>();
066        String moduleName = UNKNOWN_EXTERNAL_MODULE_NAME;
067        for (String path : files) {
068            File file = new File(path);
069            if (!file.exists()) continue; // The path here may be copying from a library root configuration, i.e. may be absent
070            try {
071                String name = file.getName();
072                if (path.charAt(0) == '@') {
073                    moduleName = path.substring(1);
074                    continue;
075                }
076
077                if (name.endsWith(".jar") || name.endsWith(".zip")) {
078                    jetFiles.addAll(readZip(file));
079                }
080                else {
081                    JetFile psiFile = JetFileUtils.createPsiFile(path, FileUtil.loadFile(file), getProject());
082                    psiFile.putUserData(EXTERNAL_MODULE_NAME, moduleName);
083                    jetFiles.add(psiFile);
084                }
085            }
086            catch (IOException e) {
087                LOG.error("While processing " + file, e);
088            }
089        }
090
091        return jetFiles;
092    }
093
094    private List<JetFile> readZip(File file) throws IOException {
095        ZipFile zipFile = new ZipFile(file);
096        try {
097            return traverseArchive(zipFile);
098        }
099        finally {
100            zipFile.close();
101        }
102    }
103
104    @NotNull
105    private List<JetFile> traverseArchive(@NotNull ZipFile file) throws IOException {
106        List<JetFile> result = Lists.newArrayList();
107        Enumeration<? extends ZipEntry> zipEntries = file.entries();
108        while (zipEntries.hasMoreElements()) {
109            ZipEntry entry = zipEntries.nextElement();
110            if (!entry.isDirectory() && entry.getName().endsWith(".kt")) {
111                InputStream stream = file.getInputStream(entry);
112                String text = FileUtil.loadTextAndClose(stream);
113                JetFile jetFile = JetFileUtils.createPsiFile(entry.getName(), text, getProject());
114                jetFile.putUserData(EXTERNAL_MODULE_NAME, UNKNOWN_EXTERNAL_MODULE_NAME);
115                result.add(jetFile);
116            }
117        }
118        return result;
119    }
120}