/* * Copyright 2018-2018 Ilya Malanin * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.intellij.plugins.haxe.codeInsight.daemon; import com.intellij.codeInsight.daemon.impl.JavaProjectSdkSetupValidator; import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.SdkModificator; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.plugins.haxe.HaxeBundle; import com.intellij.plugins.haxe.HaxeLanguage; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; import static com.intellij.plugins.haxe.codeInsight.daemon.SdkValidationResult.*; import static com.intellij.plugins.haxe.model.HaxeStdTypesFileModel.STD_TYPES_HX; public class HaxeProjectSdkSetupValidator extends JavaProjectSdkSetupValidator { @Override public boolean isApplicableFor(@NotNull Project project, @NotNull VirtualFile file) { final PsiFile psiFile = PsiManager.getInstance(project).findFile(file); return psiFile != null && psiFile.getLanguage().isKindOf(HaxeLanguage.INSTANCE); } @Nullable @Override public String getErrorMessage(@NotNull Project project, @NotNull VirtualFile file) { SdkValidationResult result = validateSdk(project, file); if (result != null) { switch (result) { case MODULE_SDK_NOT_DEFINED: return ProjectBundle.message("module.sdk.not.defined"); case PROJECT_SDK_NOT_DEFINED: return ProjectBundle.message("project.sdk.not.defined"); case MULTIPLE_ROOTS_FOUND: return HaxeBundle.message("sdk.roots.multiple"); case NO_VALID_SDK_ROOTS_FOUND: return HaxeBundle.message("sdk.roots.no.valid.root"); } } return null; } private SdkValidationResult validateSdk(Project project, VirtualFile file) { final Module module = ModuleUtilCore.findModuleForFile(file, project); if (module != null && !module.isDisposed()) { final Sdk sdk = ModuleRootManager.getInstance(module).getSdk(); if (sdk == null) { if (ModuleRootManager.getInstance(module).isSdkInherited()) { return PROJECT_SDK_NOT_DEFINED; } else { return MODULE_SDK_NOT_DEFINED; } } else { return validateSdkRoots(sdk); } } return null; } private SdkValidationResult validateSdkRoots(Sdk sdk) { List<VirtualFile> roots = getDistinctRoots(sdk); if (hasNoValidRoots(roots)) { return NO_VALID_SDK_ROOTS_FOUND; } if (hasMultipleOrEmptyRoots(roots)) { return MULTIPLE_ROOTS_FOUND; } return null; } private List<VirtualFile> getDistinctRoots(Sdk sdk) { return getDistinctRootsStream(sdk).collect(Collectors.toList()); } private Stream<VirtualFile> getDistinctRootsStream(Sdk sdk) { return Stream.concat( Arrays.stream(sdk.getRootProvider().getFiles(OrderRootType.CLASSES)), Arrays.stream(sdk.getRootProvider().getFiles(OrderRootType.SOURCES)) ).distinct(); } private boolean hasNoValidRoots(List<VirtualFile> roots) { return roots.stream().noneMatch(root -> root.findChild(STD_TYPES_HX) != null); } private boolean hasMultipleOrEmptyRoots(List<VirtualFile> roots) { return roots.size() != 1; } @Override public void doFix(@NotNull Project project, @NotNull VirtualFile file) { SdkValidationResult result = validateSdk(project, file); if (result == null) { return; } switch (result) { case PROJECT_SDK_NOT_DEFINED: case MODULE_SDK_NOT_DEFINED: case NO_VALID_SDK_ROOTS_FOUND: super.doFix(project, file); break; case MULTIPLE_ROOTS_FOUND: pruneExcessiveRoots(project, file); break; } } private void pruneExcessiveRoots(Project project, VirtualFile file) { final Module module = ModuleUtilCore.findModuleForFile(file, project); if (module != null && !module.isDisposed()) { final Sdk sdk = ModuleRootManager.getInstance(module).getSdk(); if (sdk != null) { final SdkModificator modificator = sdk.getSdkModificator(); final VirtualFile stdRoot = getDistinctRootsStream(sdk) .filter(root -> root.findChild(STD_TYPES_HX) != null) .findFirst() .orElse(null); if (stdRoot != null) { modificator.removeAllRoots(); modificator.addRoot(stdRoot, OrderRootType.CLASSES); modificator.addRoot(stdRoot, OrderRootType.SOURCES); WriteAction.run(modificator::commitChanges); } } } } } enum SdkValidationResult { PROJECT_SDK_NOT_DEFINED, MODULE_SDK_NOT_DEFINED, MULTIPLE_ROOTS_FOUND, NO_VALID_SDK_ROOTS_FOUND }