package org.elixir_lang; import com.intellij.openapi.projectRoots.*; import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.Version; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; import java.util.*; import java.util.List; public class SdkType extends com.intellij.openapi.projectRoots.SdkType { @NotNull public static SdkType getInstance() { return com.intellij.openapi.projectRoots.SdkType.findInstance(SdkType.class); } public static boolean pathIsValidSdkHome(String path) { File bin = new File(path, "bin").getAbsoluteFile(); File elixir = new File(bin, "elixir"); File elixirc = new File(bin, "elixirc"); File iex = new File(bin, "iex"); File mix = new File(bin, "mix"); return elixir.canExecute() && elixirc.canExecute() && iex.canExecute() && mix.canExecute(); } SdkType() { super("Elixir SDK"); } @Nullable @Override public AdditionalDataConfigurable createAdditionalDataConfigurable(SdkModel sdkModel, SdkModificator sdkModificator) { return null; } @Override public String getPresentableName() { return "Elixir SDK"; } @Override public boolean isValidSdkHome(String path) { return pathIsValidSdkHome(path); } @Nullable @Override public String getVersionString(String sdkHome) { List<String> parts = FileUtil.splitPath(sdkHome); return parts.get(parts.size() - 1); } @Override public void saveAdditionalData(@NotNull SdkAdditionalData additionalData, @NotNull Element additional) { // No additionalData } @Nullable @Override public String suggestHomePath() { Iterator<String> iterator = suggestHomePaths().iterator(); String suggestedHomePath = null; if (iterator.hasNext()) { suggestedHomePath = iterator.next(); } return suggestedHomePath; } @Override public Collection<String> suggestHomePaths() { return homePathByVersion().values(); } @Override public String suggestSdkName(String currentSdkName, String sdkHome) { return "Elixir " + getVersionString(sdkHome); } @Override public void setupSdkPaths(@NotNull Sdk sdk) { SdkModificator sdkModificator = sdk.getSdkModificator(); String sdkHome = sdkModificator.getHomePath(); File lib = new File(sdkHome, "lib"); //noinspection ConstantConditions for (File library : lib.listFiles()) { File beams = new File(library, "ebin"); if (beams.isDirectory()) { VirtualFile libraryVirtualFile = LocalFileSystem.getInstance().findFileByIoFile(library); if (libraryVirtualFile != null) { sdkModificator.addRoot(libraryVirtualFile, OrderRootType.CLASSES); } } } sdkModificator.commitChanges(); } /* * Private */ /** * Map of home paths to versions in descending version order so that newer versions are favored. * * @return */ private Map<Version, String> homePathByVersion() { Map<Version, String> homePathByVersion = new TreeMap<Version, String>( new Comparator<Version>() { @Override public int compare(Version version1, Version version2) { // compare version2 to version1 to produce descending instead of ascending order. return version2.compareTo(version1); } } ); if (SystemInfo.isMac) { File homebrewRoot = new File("/usr/local/Cellar/elixir"); if (homebrewRoot.isDirectory()) { //noinspection ConstantConditions for (File child : homebrewRoot.listFiles()) { if (child.isDirectory()) { String versionString = child.getName(); String[] versionParts = versionString.split("\\.", 3); int major = Integer.parseInt(versionParts[0]); int minor = Integer.parseInt(versionParts[1]); int bugfix = Integer.parseInt(versionParts[2]); Version version = new Version(major, minor, bugfix); homePathByVersion.put(version, child.getAbsolutePath()); } } } } return homePathByVersion; } }