package com.siberika.idea.pascal.sdk; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.projectRoots.AdditionalDataConfigurable; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.SdkModel; import com.intellij.openapi.projectRoots.SdkModificator; import com.intellij.openapi.projectRoots.SdkType; import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.siberika.idea.pascal.PascalException; import com.siberika.idea.pascal.PascalIcons; import com.siberika.idea.pascal.jps.model.JpsPascalModelSerializerExtension; import com.siberika.idea.pascal.jps.sdk.PascalCompilerFamily; import com.siberika.idea.pascal.jps.sdk.PascalSdkData; import com.siberika.idea.pascal.jps.sdk.PascalSdkUtil; import com.siberika.idea.pascal.util.SysUtils; import org.apache.commons.lang.SystemUtils; import org.apache.commons.lang.text.StrBuilder; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.io.File; import java.util.Arrays; import java.util.List; /** * Author: George Bakhtadze * Date: 10/01/2013 */ public class FPCSdkType extends BasePascalSdkType { private static final Logger LOG = Logger.getInstance(FPCSdkType.class.getName()); private static final String[] LIBRARY_DIRS = {"rtl", "rtl-objpas", "pthreads", "regexpr", "x11", "windows"}; @NotNull public static FPCSdkType getInstance() { return SdkType.findInstance(FPCSdkType.class); } public FPCSdkType() { super(JpsPascalModelSerializerExtension.FPC_SDK_TYPE_ID, PascalCompilerFamily.FPC); loadResources("fpc"); } @Nullable @Override public String suggestHomePath() { List<String> paths = Arrays.asList("/usr/lib/codetyphon/fpc/fpc32", "/usr/lib/codetyphon/fpc", "/usr/lib/fpc", "/usr/share/fpc", "/usr/local/lib/fpc"); if (SystemInfo.isWindows) { paths = Arrays.asList("c:\\codetyphon\\fpc\\fpc32", "c:\\codetyphon\\fpc", "c:\\fpc"); } for (String path : paths) { if (new File(path).isDirectory()) { return path; } } return null; } @NotNull @Override public Icon getIcon() { return PascalIcons.GENERAL; } @NotNull @Override public Icon getIconForAddAction() { return getIcon(); } @Override public boolean isValidSdkHome(@NotNull final String path) { LOG.info("Checking SDK path: " + path); final File fpcExe = PascalSdkUtil.getFPCExecutable(path); return fpcExe.isFile() && fpcExe.canExecute(); } @NotNull public String suggestSdkName(@Nullable final String currentSdkName, @NotNull final String sdkHome) { String version = getVersionString(sdkHome); if (version == null) return "Free Pascal v. ?? at " + sdkHome; return "Free Pascal v. " + version + " | " + getTargetString(sdkHome); } @Nullable public String getVersionString(String sdkHome) { LOG.info("Getting version for SDK path: " + sdkHome); try { return SysUtils.runAndGetStdOut(sdkHome, PascalSdkUtil.getFPCExecutable(sdkHome).getAbsolutePath(), PascalSdkUtil.FPC_PARAMS_VERSION_GET); } catch (PascalException e) { LOG.info("Error: " + e.getMessage(), e); } catch (RuntimeException e) { LOG.info("Error: " + e.getMessage(), e); } return null; } @Nullable private static String getTargetString(String sdkHome) { LOG.info("Getting target for SDK path: " + sdkHome); try { return SysUtils.runAndGetStdOut(sdkHome, PascalSdkUtil.getFPCExecutable(sdkHome).getAbsolutePath(), PascalSdkUtil.FPC_PARAMS_TARGET_GET); } catch (PascalException e) { LOG.info("Error: " + e.getMessage(), e); } return null; } @NotNull @NonNls @Override public String getPresentableName() { return "Free Pascal SDK"; } @Override public void setupSdkPaths(@NotNull final Sdk sdk) { String target = getTargetString(sdk.getHomePath()); configureSdkPaths(sdk, target); configureOptions(sdk, getAdditionalData(sdk), target); } @Override protected void configureOptions(@NotNull Sdk sdk, PascalSdkData data, String target) { super.configureOptions(sdk, data, target); File file = PascalSdkUtil.getPPUDumpExecutable(sdk.getHomePath() != null ? sdk.getHomePath() : ""); data.setValue(PascalSdkData.Keys.DECOMPILER_COMMAND.getKey(), file.getAbsolutePath()); StrBuilder sb = new StrBuilder(); if (SystemUtils.IS_OS_WINDOWS) { sb.append("-dMSWINDOWS "); } else { sb.append("-dPOSIX "); if (SystemUtils.IS_OS_MAC_OSX) { sb.append("-dMACOS "); } else { sb.append("-dLINUX "); } } if (target.contains("_64")) { sb.append("-dCPUX64 "); } else { sb.append("-dCPUX86 "); } data.setValue(PascalSdkData.Keys.COMPILER_OPTIONS.getKey(), sb.toString()); } private static void configureSdkPaths(@NotNull final Sdk sdk, String target) { LOG.info("Setting up SDK paths for SDK at " + sdk.getHomePath()); final SdkModificator[] sdkModificatorHolder = new SdkModificator[]{null}; final SdkModificator sdkModificator = sdk.getSdkModificator(); if (target != null) { target = target.replace(' ', '-'); for (String dir : LIBRARY_DIRS) { VirtualFile vdir = getLibrary(sdk, target, dir); if (vdir != null) { sdkModificator.addRoot(vdir, OrderRootType.CLASSES); } } sdkModificatorHolder[0] = sdkModificator; sdkModificatorHolder[0].commitChanges(); } } private static VirtualFile getLibrary(Sdk sdk, String target, String name) { File rtlDir = new File(sdk.getHomePath() + File.separatorChar + "units" + File.separatorChar + target + File.separatorChar + name); if (!rtlDir.exists()) { rtlDir = new File(sdk.getHomePath() + File.separatorChar + sdk.getVersionString() + File.separatorChar + "units" + File.separatorChar + target + File.separatorChar + name); } return LocalFileSystem.getInstance().findFileByIoFile(rtlDir); } @Override public boolean isRootTypeApplicable(@NotNull OrderRootType type) { return type.equals(OrderRootType.SOURCES) || type.equals(OrderRootType.CLASSES); } @Nullable @Override public AdditionalDataConfigurable createAdditionalDataConfigurable(@NotNull final SdkModel sdkModel, @NotNull final SdkModificator sdkModificator) { return new PascalSdkConfigUI(); } }