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.jet.utils;
018
019import com.intellij.openapi.application.PathManager;
020import com.intellij.openapi.util.SystemInfo;
021import com.intellij.openapi.util.io.FileUtil;
022import com.intellij.openapi.vfs.VirtualFile;
023import com.intellij.openapi.vfs.VirtualFileManager;
024import org.jetbrains.annotations.NotNull;
025
026import java.io.File;
027
028public class PathUtil {
029
030    public static final String JPS_KOTLIN_HOME_PROPERTY = "jps.kotlin.home";
031
032    public static final String JS_LIB_JAR_NAME = "kotlin-jslib.jar";
033    public static final String JS_LIB_JS_NAME = "kotlinEcma3.js";
034    public static final String JDK_ANNOTATIONS_JAR = "kotlin-jdk-annotations.jar";
035    public static final String ANDROID_SDK_ANNOTATIONS_JAR = "kotlin-android-sdk-annotations.jar";
036    public static final String KOTLIN_JAVA_RUNTIME_JAR = "kotlin-runtime.jar";
037    public static final String HOME_FOLDER_NAME = "kotlinc";
038
039    private static final File NO_PATH = new File("<no_path>");
040
041    private PathUtil() {}
042
043    @NotNull
044    public static KotlinPaths getKotlinPathsForIdeaPlugin() {
045        return new KotlinPathsFromHomeDir(getCompilerPathForIdeaPlugin());
046    }
047
048    @NotNull
049    public static KotlinPaths getKotlinPathsForJpsPlugin() {
050        // When JPS is run on TeamCity, it can not rely on Kotlin plugin layout,
051        // so the path to Kotlin is specified in a system property
052        String jpsKotlinHome = System.getProperty(JPS_KOTLIN_HOME_PROPERTY);
053        if (jpsKotlinHome != null) {
054            return new KotlinPathsFromHomeDir(new File(jpsKotlinHome));
055        }
056        return new KotlinPathsFromHomeDir(getCompilerPathForJpsPlugin());
057    }
058
059    @NotNull
060    public static KotlinPaths getKotlinPathsForJpsPluginOrJpsTests() {
061        if ("true".equalsIgnoreCase(System.getProperty("kotlin.jps.tests"))) {
062            return getKotlinPathsForDistDirectory();
063        }
064        return getKotlinPathsForJpsPlugin();
065    }
066
067    @NotNull
068    public static KotlinPaths getKotlinPathsForCompiler() {
069        if (!getPathUtilJar().isFile()) {
070            // Not running from a jar, i.e. it is it must be a unit test
071            return getKotlinPathsForDistDirectory();
072        }
073        return new KotlinPathsFromHomeDir(getCompilerPathForCompilerJar());
074    }
075
076    @NotNull
077    public static KotlinPaths getKotlinPathsForDistDirectory() {
078        return new KotlinPathsFromHomeDir(new File("dist", HOME_FOLDER_NAME));
079    }
080
081    @NotNull
082    private static File getCompilerPathForCompilerJar() {
083        File jar = getPathUtilJar();
084
085        if (!jar.exists()) return NO_PATH;
086
087        if (jar.getName().equals("kotlin-compiler.jar")) {
088            File lib = jar.getParentFile();
089            return lib.getParentFile();
090        }
091
092        return NO_PATH;
093    }
094
095    @NotNull
096    private static File getCompilerPathForJpsPlugin() {
097        File jar = getPathUtilJar();
098
099        if (!jar.exists()) return NO_PATH;
100
101        if (jar.getName().equals("kotlin-jps-plugin.jar")) {
102            File pluginHome = jar.getParentFile().getParentFile().getParentFile();
103            return new File(pluginHome, HOME_FOLDER_NAME);
104        }
105
106        return NO_PATH;
107    }
108
109    @NotNull
110    private static File getCompilerPathForIdeaPlugin() {
111        File jar = getPathUtilJar();
112
113        if (!jar.exists()) return NO_PATH;
114
115        if (jar.getName().equals("kotlin-plugin.jar")) {
116            File lib = jar.getParentFile();
117            File pluginHome = lib.getParentFile();
118
119            return new File(pluginHome, HOME_FOLDER_NAME);
120        }
121
122        return NO_PATH;
123    }
124
125    private static File getPathUtilJar() {
126        return getJarPathForClass(PathUtil.class);
127    }
128
129    @NotNull
130    public static File getJarPathForClass(@NotNull Class aClass) {
131        String resourceRoot = PathManager.getResourceRoot(aClass, "/" + aClass.getName().replace('.', '/') + ".class");
132        return new File(resourceRoot).getAbsoluteFile();
133    }
134
135    @NotNull
136    public static VirtualFile jarFileOrDirectoryToVirtualFile(@NotNull File file) {
137        if (file.exists()) {
138            if (file.isDirectory()) {
139                return VirtualFileManager.getInstance()
140                        .findFileByUrl("file://" + FileUtil.toSystemIndependentName(file.getAbsolutePath()));
141            }
142            else {
143                return VirtualFileManager.getInstance().findFileByUrl("jar://" + FileUtil.toSystemIndependentName(file.getAbsolutePath()) + "!/");
144            }
145        }
146        else {
147            throw new IllegalStateException("Path " + file + " does not exist.");
148        }
149    }
150
151    @NotNull
152    public static File findRtJar() {
153        return findRtJar(System.getProperty("java.home"));
154    }
155
156    private static File findRtJar(String javaHome) {
157        if (SystemInfo.isMac && !SystemInfo.isJavaVersionAtLeast("1.7")) {
158            File classesJar = new File(new File(javaHome).getParentFile(), "Classes/classes.jar");
159            if (classesJar.exists()) {
160                return classesJar;
161            }
162
163            throw new IllegalArgumentException("No classes.jar found under " + classesJar.getParent());
164        }
165        else {
166            File rtJar = new File(javaHome, "lib/rt.jar");
167            if (rtJar.exists()) {
168                return rtJar;
169            }
170
171            throw new IllegalArgumentException("No rt.jar found under " + rtJar.getParent());
172        }
173    }
174}