diff --git a/src/main/java/com/intellij/plugins/haxe/haxelib/HaxeLibrary.java b/src/main/java/com/intellij/plugins/haxe/haxelib/HaxeLibrary.java index 921eb4598..dd825feb5 100644 --- a/src/main/java/com/intellij/plugins/haxe/haxelib/HaxeLibrary.java +++ b/src/main/java/com/intellij/plugins/haxe/haxelib/HaxeLibrary.java @@ -39,7 +39,7 @@ public class HaxeLibrary { private static String CURRENT_DIR = "."; - final private ProjectLibraryCache myCache; + final private ModuleLibraryCache myCache; final private String myName; final private String myLibraryRoot; final private String myRelativeClasspath; @@ -48,12 +48,12 @@ public class HaxeLibrary { // TODO: Add the extraParams.hxml data here. Use the hxml parser; see LimeUtil.getLimeProjectModel() as an example. - private HaxeLibrary(@NotNull String name, @NotNull VirtualFile libraryRoot, @NotNull ProjectLibraryCache owner) { + private HaxeLibrary(@NotNull String name, @NotNull VirtualFile libraryRoot, @NotNull ModuleLibraryCache owner) { myCache = owner; myLibraryRoot = libraryRoot.getUrl(); myMetadata = HaxelibMetadata.load(libraryRoot); - HaxeLibraryInfo pathInfo = HaxelibUtil.deriveLibraryInfoFromPath(owner.getSdk(), libraryRoot.getPath()); + HaxeLibraryInfo pathInfo = HaxelibUtil.deriveLibraryInfoFromPath(owner, libraryRoot.getPath()); String mdname = myMetadata.getName(); if (null != mdname && !mdname.isEmpty()) { @@ -185,9 +185,9 @@ public HaxelibSemVer getVersion() { * @return the loaded HaxeLibrary of the given name; null if not found. */ @Nullable - public static HaxeLibrary load(ProjectLibraryCache owner, String libName, String libVersion, Sdk sdk) { + public static HaxeLibrary load(ModuleLibraryCache owner, String libName, String libVersion, Sdk sdk) { // Ask haxelib for the path to this library. - VirtualFile libraryRoot = HaxelibUtil.getLibraryRoot(sdk, libName,libVersion); + VirtualFile libraryRoot = HaxelibUtil.getLibraryRoot(sdk,owner, libName,libVersion); if (null == libraryRoot) { // XXX: This case might occur if the library is not managed by haxelib, but then // that should be a classpath, not a lib. diff --git a/src/main/java/com/intellij/plugins/haxe/haxelib/HaxeLibraryDependency.java b/src/main/java/com/intellij/plugins/haxe/haxelib/HaxeLibraryDependency.java index 5695cd82a..9e5ff110c 100644 --- a/src/main/java/com/intellij/plugins/haxe/haxelib/HaxeLibraryDependency.java +++ b/src/main/java/com/intellij/plugins/haxe/haxelib/HaxeLibraryDependency.java @@ -35,7 +35,7 @@ public HaxeLibraryDependency(@NotNull Module module, @NotNull String name, @Null this(HaxelibProjectUpdater.getLibraryCache(module), name, semver, reliant); } - public HaxeLibraryDependency(@NotNull ProjectLibraryCache owner, @NotNull String name, @Nullable String semver, @Nullable HaxeLibrary reliant) { + public HaxeLibraryDependency(@NotNull ModuleLibraryCache owner, @NotNull String name, @Nullable String semver, @Nullable HaxeLibrary reliant) { super(owner, name, HaxelibSemVer.create(semver), false); reliants = new HaxeLibraryList(owner.getSdk()); if (null != reliant) { @@ -43,7 +43,7 @@ public HaxeLibraryDependency(@NotNull ProjectLibraryCache owner, @NotNull String } } - public HaxeLibraryDependency(@NotNull ProjectLibraryCache owner, @NotNull String name, @Nullable String semver, @NotNull HaxeLibraryList reliants) { + public HaxeLibraryDependency(@NotNull ModuleLibraryCache owner, @NotNull String name, @Nullable String semver, @NotNull HaxeLibraryList reliants) { this(owner, name, semver, (HaxeLibrary)null); this.reliants.addAll(reliants); } diff --git a/src/main/java/com/intellij/plugins/haxe/haxelib/HaxeLibraryReference.java b/src/main/java/com/intellij/plugins/haxe/haxelib/HaxeLibraryReference.java index 83cc5131e..ba41985fd 100644 --- a/src/main/java/com/intellij/plugins/haxe/haxelib/HaxeLibraryReference.java +++ b/src/main/java/com/intellij/plugins/haxe/haxelib/HaxeLibraryReference.java @@ -42,7 +42,7 @@ public class HaxeLibraryReference { } protected final String name; - protected final ProjectLibraryCache owner; + protected final ModuleLibraryCache owner; protected final HaxelibSemVer semver; protected final AtomicBoolean isManaged = new AtomicBoolean(false); @@ -51,7 +51,7 @@ public HaxeLibraryReference(@NotNull Module module, @NotNull String libName, @No this(module, libName, semver, false); } - public HaxeLibraryReference(@NotNull ProjectLibraryCache owner, @NotNull String libName, @NotNull HaxelibSemVer semver) { + public HaxeLibraryReference(@NotNull ModuleLibraryCache owner, @NotNull String libName, @NotNull HaxelibSemVer semver) { this(owner, libName, semver, false); } @@ -59,7 +59,7 @@ public HaxeLibraryReference(@NotNull Module module, @NotNull String libName, @No this(HaxelibProjectUpdater.getLibraryCache(module), libName, semver, isManaged); } - public HaxeLibraryReference(@NotNull ProjectLibraryCache owner, + public HaxeLibraryReference(@NotNull ModuleLibraryCache owner, @NotNull String libName, @NotNull HaxelibSemVer semver, boolean isManaged) { @@ -76,12 +76,12 @@ public HaxeLibraryReference clone() { } public static HaxeLibraryReference create(@NotNull Module module, @NotNull String name) { - ProjectLibraryCache owner = HaxelibProjectUpdater.getLibraryCache(module); + ModuleLibraryCache owner = HaxelibProjectUpdater.getLibraryCache(module); return create(owner, name); } - public static HaxeLibraryReference create(@NotNull ProjectLibraryCache owner, @NotNull String name) { + public static HaxeLibraryReference create(@NotNull ModuleLibraryCache owner, @NotNull String name) { if (name.isEmpty()) { return null; } @@ -118,7 +118,7 @@ public String getName() { * @return the Cache that owns the reference (as given at instantiation). */ @NotNull - public ProjectLibraryCache getOwner() { + public ModuleLibraryCache getOwner() { return owner; } diff --git a/src/main/java/com/intellij/plugins/haxe/haxelib/HaxelibCacheManager.java b/src/main/java/com/intellij/plugins/haxe/haxelib/HaxelibCacheManager.java index 3501d7330..e140c567c 100644 --- a/src/main/java/com/intellij/plugins/haxe/haxelib/HaxelibCacheManager.java +++ b/src/main/java/com/intellij/plugins/haxe/haxelib/HaxelibCacheManager.java @@ -1,7 +1,9 @@ package com.intellij.plugins.haxe.haxelib; import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.ProjectUtil; import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.vfs.VirtualFile; import lombok.CustomLog; import org.jetbrains.annotations.NotNull; @@ -19,7 +21,7 @@ public class HaxelibCacheManager { // current version of haxelib shows versions as date + version + description private static Pattern HAXELIB_VERSION_LINE = - Pattern.compile("(?\\d{4}-\\d{2}-\\d{2}\s\\d{2}:\\d{2}:\\d{2})\s(?.*)\s:\s(?.*)"); + Pattern.compile("(?\\d{4}-\\d{2}-\\d{2}\s\\d{2}:\\d{2}:\\d{2})\s(?.*?)\s:\s(?.*)"); private static Map instances = new HashMap<>(); @@ -103,8 +105,9 @@ private static Map> readAvailableOnline(Sdk sdk) { return libMap; } - private static Map> readInstalledLibraries(@NotNull Sdk sdk) { - HaxelibInstalledIndex index = HaxelibInstalledIndex.fetchFromHaxelib(sdk); + private Map> readInstalledLibraries(@NotNull Sdk sdk) { + VirtualFile file = ProjectUtil.guessModuleDir(module); + HaxelibInstalledIndex index = HaxelibInstalledIndex.fetchFromHaxelib(sdk, file); return index.getInstalledLibrariesAndVersions(); } @@ -116,7 +119,8 @@ public Set fetchAvailableVersions(String name) { log.warn("Unable to fetch Available Versions, invalid SDK paths"); return Set.of(); } - List list = HaxelibCommandUtils.issueHaxelibCommand(sdk, "info", name); + VirtualFile file = ProjectUtil.guessModuleDir(module); + List list = HaxelibCommandUtils.issueHaxelibCommand(sdk, file,"info", name); // filter to find version numbers Set versions = list.stream() diff --git a/src/main/java/com/intellij/plugins/haxe/haxelib/HaxelibClasspathUtils.java b/src/main/java/com/intellij/plugins/haxe/haxelib/HaxelibClasspathUtils.java index 75251e3f8..28a7f9d6b 100644 --- a/src/main/java/com/intellij/plugins/haxe/haxelib/HaxelibClasspathUtils.java +++ b/src/main/java/com/intellij/plugins/haxe/haxelib/HaxelibClasspathUtils.java @@ -279,65 +279,17 @@ public static HaxeClasspath getFullClasspath(@NotNull Module module) { } - /** - * Locate files and dependencies using 'haxelib path ' - * - * @param name name of the base file or library to search for. - * @return a set of path name URLs, may be an empty list. - */ - @NotNull - public static List getHaxelibLibraryPathUrl(@NotNull Sdk sdk, @NotNull String name) { - List strings = HaxelibCommandUtils.issueHaxelibCommand(sdk, "path", - name); - List classpathUrls = new ArrayList(strings.size()); - - for (String string : strings) { - if (isClassPathLine(string)) { - VirtualFile file = LocalFileFinder.findFile(string); - if (file != null) { - classpathUrls.add(file.getUrl()); - } - } - } - - return classpathUrls; - } - - /** - * Locate files and dependencies using 'haxelib path ' - * - * @param name name of the base file or library to search for. - * @return a set of HaxelibItems, may be an empty list. - */ - @NotNull - public static HaxeClasspath getHaxelibLibraryPath(@NotNull Sdk sdk, @NotNull String name) { - List strings = HaxelibCommandUtils.issueHaxelibCommand(sdk, "path", name); - HaxeClasspath classpath = new HaxeClasspath(strings.size()); - - for (String string : strings) { - if (isClassPathLine(string)) { - VirtualFile file = LocalFileFinder.findFile(string); - if (file != null) { - // There are no duplicates in the return from haxelib, so no need to check contains(). - classpath.add(new HaxelibItem(file.getPath(), file.getUrl())); - } - } - } - - return classpath; - } - /** * Local classpaths of specified libraries and their dependencies. */ - public static Set getHaxelibLibrariesClasspaths(@NotNull Sdk sdk, String... libNames) { + public static Set getHaxelibLibrariesClasspaths(@NotNull Sdk sdk,VirtualFile workDir, String... libNames) { Set result = new HashSet<>(); ArrayList args = new ArrayList<>(); args.add("path"); Collections.addAll(args, libNames); - List out = HaxelibCommandUtils.issueHaxelibCommand(sdk, args.toArray(new String[0])); + List out = HaxelibCommandUtils.issueHaxelibCommand(sdk,workDir, args.toArray(new String[0])); for(String line:out) { if(!isClassPathLine(line)) { continue; @@ -361,7 +313,7 @@ public static Set getHaxelibLibrariesClasspaths(@NotNull Sdk sdk, String */ @NotNull public static List getAvailableLibrariesMatching(@NotNull Sdk sdk, @NotNull String word) { - List stringList = HaxelibCommandUtils.issueHaxelibCommand(sdk, "search", word); + List stringList = HaxelibCommandUtils.issueHaxelibCommand(sdk, null,"search", word); if (stringList.size() > 0) { // Last line is the count of libraries found. stringList.remove(stringList.size() - 1); @@ -381,7 +333,7 @@ public static List getAvailableLibrariesMatching(@NotNull Sdk sdk, @NotN public static List getProjectDisplayInformation(@NotNull Module module, @NotNull File dir, @NotNull String executable, @NotNull Sdk sdk) { List strings1 = Collections.EMPTY_LIST; - ProjectLibraryCache cache = HaxelibProjectUpdater.getLibraryCache(module); + ModuleLibraryCache cache = HaxelibProjectUpdater.getLibraryCache(module); if (cache != null && cache.libraryIsInstalled(executable)) { ArrayList commandLineArguments = new ArrayList(); commandLineArguments.add(HaxelibCommandUtils.getHaxelibPath(sdk)); diff --git a/src/main/java/com/intellij/plugins/haxe/haxelib/HaxelibCommandUtils.java b/src/main/java/com/intellij/plugins/haxe/haxelib/HaxelibCommandUtils.java index 1dc567ace..ee0b0f0fc 100644 --- a/src/main/java/com/intellij/plugins/haxe/haxelib/HaxelibCommandUtils.java +++ b/src/main/java/com/intellij/plugins/haxe/haxelib/HaxelibCommandUtils.java @@ -98,11 +98,11 @@ public static String getHaxelibPath(@NotNull Sdk sdk) { */ @NotNull - public static List issueHaxelibCommand(@NotNull Sdk sdk, String... args) { + public static List issueHaxelibCommand(@NotNull Sdk sdk, @Nullable VirtualFile workDir, String... args) { Application application = ApplicationManager.getApplication(); if (application.isDispatchThread()) { List result = new ArrayList<>(); - ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> result.addAll(_issueHaxelibCommand(sdk, args)), + ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> result.addAll(_issueHaxelibCommand(sdk,workDir, args)), "Haxelib Command", false, null); return result; } @@ -111,7 +111,7 @@ else if (application.isReadAccessAllowed()) { // TODO: this is a hacky way to get around the `checkEdtAndReadAction` check, // while we move the logic to another thread we block the current one using get(), preferred // method would be some kind of callback - return application.executeOnPooledThread(()-> _issueHaxelibCommand(sdk, args)).get(); + return application.executeOnPooledThread(()-> _issueHaxelibCommand(sdk, workDir, args)).get(); } catch (InterruptedException e) { throw new RuntimeException(e); @@ -121,13 +121,13 @@ else if (application.isReadAccessAllowed()) { } } else { - return _issueHaxelibCommand(sdk, args); + return _issueHaxelibCommand(sdk, workDir, args); } } @NotNull - private static List _issueHaxelibCommand(@NotNull Sdk sdk, String... args) { + private static List _issueHaxelibCommand(@NotNull Sdk sdk, @Nullable VirtualFile workDir, String... args) { // TODO: Wrap the process with a timer? @@ -144,15 +144,17 @@ private static List _issueHaxelibCommand(@NotNull Sdk sdk, String... arg // TODO mlo: try to clean up code so it only uses either dir or file File haxelibCmd = new File(haxelibPath); - VirtualFile dir = haxelibCmd.isFile() - ? LocalFileSystem.getInstance().findFileByPath(haxelibCmd.getParent()) - : LocalFileSystem.getInstance().findFileByPath(haxelibPath); - if (dir == null) { + if(workDir == null) { + workDir = haxelibCmd.isFile() + ? LocalFileSystem.getInstance().findFileByPath(haxelibCmd.getParent()) + : LocalFileSystem.getInstance().findFileByPath(haxelibPath); + } + if (workDir == null) { log.error("unable to execute haxelib command, haxelib path is null"); return List.of(); } List stdout = new ArrayList(); - int exitvalue = HaxeProcessUtil.runProcess(commandLineArguments, true, dir, sdkData, + int exitvalue = HaxeProcessUtil.runProcess(commandLineArguments, true, workDir, sdkData, stdout, null, null, false); if (0 != exitvalue) { diff --git a/src/main/java/com/intellij/plugins/haxe/haxelib/HaxelibInstalledIndex.java b/src/main/java/com/intellij/plugins/haxe/haxelib/HaxelibInstalledIndex.java index fd38a6e1c..21fcf48c2 100644 --- a/src/main/java/com/intellij/plugins/haxe/haxelib/HaxelibInstalledIndex.java +++ b/src/main/java/com/intellij/plugins/haxe/haxelib/HaxelibInstalledIndex.java @@ -1,6 +1,7 @@ package com.intellij.plugins.haxe.haxelib; import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -39,7 +40,7 @@ public String getSelectedVersion(String Library) { return selectedVersions.getOrDefault(Library, null); } - public static HaxelibInstalledIndex fetchFromHaxelib(@NotNull Sdk sdk){ + public static HaxelibInstalledIndex fetchFromHaxelib(@NotNull Sdk sdk, VirtualFile workDir){ // haxelib list output looks like: // lime-tools: 1.4.0 [1.5.6] // The library name comes first, followed by a colon, followed by a @@ -47,7 +48,7 @@ public static HaxelibInstalledIndex fetchFromHaxelib(@NotNull Sdk sdk){ HaxelibInstalledIndex index = new HaxelibInstalledIndex(); - List listCmdOutput = HaxelibCommandUtils.issueHaxelibCommand(sdk, "list"); + List listCmdOutput = HaxelibCommandUtils.issueHaxelibCommand(sdk, workDir, "list"); if ((listCmdOutput.size() > 0) && (!listCmdOutput.get(0).contains("Unknown command"))) { for (String line : listCmdOutput) { int firstColon = line.indexOf(":"); diff --git a/src/main/java/com/intellij/plugins/haxe/haxelib/HaxelibModuleManagerService.java b/src/main/java/com/intellij/plugins/haxe/haxelib/HaxelibModuleManagerService.java index 74c61afce..63f8f241e 100644 --- a/src/main/java/com/intellij/plugins/haxe/haxelib/HaxelibModuleManagerService.java +++ b/src/main/java/com/intellij/plugins/haxe/haxelib/HaxelibModuleManagerService.java @@ -79,6 +79,7 @@ public void modulesAdded(@NotNull Project project, @NotNull List { @@ -561,7 +561,7 @@ private static void syncHxml(@NotNull Module module, @NotNull HaxeDebugTimeLog timeLog, Project project, HaxeLibraryList haxelibExternalItems, - ProjectLibraryCache libManager, HaxeModuleSettings settings) { + ModuleLibraryCache libManager, HaxeModuleSettings settings) { timeLog.stamp("Start loading haxelibs from HXML file."); String hxmlPath = settings.getHxmlPath(); @@ -610,7 +610,7 @@ private static void syncOpenFLModule(@NotNull Module module, @NotNull HaxeDebugTimeLog timeLog, Project project, HaxeLibraryList haxelibExternalItems, - ProjectLibraryCache libManager, + ModuleLibraryCache libManager, HaxeModuleSettings settings) { timeLog.stamp("Start loading haxelibs from openFL configuration file."); //TODO mlo: we should rewrite this and change it from openFL to Lime, and lime does not require this lib @@ -688,7 +688,7 @@ private static void syncNMMLModule(@NotNull Module module, @NotNull HaxeDebugTimeLog timeLog, Project project, HaxeLibraryList haxelibExternalItems, - ProjectLibraryCache libManager, + ModuleLibraryCache libManager, HaxeModuleSettings settings) { timeLog.stamp("Start loading haxelibs from NMML file."); HaxeLibrary nme = libManager.getLibrary("nme", HaxelibSemVer.ANY_VERSION); @@ -1210,7 +1210,7 @@ public final class ProjectTracker implements Disposable { boolean myIsDirty; boolean myIsUpdating; ProjectLibraryListCache myCache; - ProjectLibraryCacheManager mySdkManager; + ProjectLibraryCacheManager myLibraryCacheManager; // TODO: Determine if we need to track whether the project is still open. @@ -1228,7 +1228,7 @@ public ProjectTracker(Project project) { myIsUpdating = false; myReferenceCount = 0; myCache = new ProjectLibraryListCache(HaxelibSdkUtils.lookupSdk(project)); - mySdkManager = new ProjectLibraryCacheManager(); + myLibraryCacheManager = new ProjectLibraryCacheManager(); VirtualFileManager mgr = VirtualFileManager.getInstance(); mgr.addAsyncFileListener(this::lookForLibChanges, project); @@ -1246,8 +1246,8 @@ public HaxelibProjectUpdater.ProjectLibraryListCache getCache() { * Get the library classpath cache. */ @NotNull - public ProjectLibraryCacheManager getSdkManager() { - return mySdkManager; + public ProjectLibraryCacheManager getLibraryManager() { + return myLibraryCacheManager; } /** @@ -1280,6 +1280,7 @@ public boolean setDirty(boolean newState) { // the project. In that case, we would want to detect whether // the project settings really changed, and act accordingly. myCache.clear(); + myLibraryCacheManager.clear(); } } return ret; @@ -1408,6 +1409,12 @@ private String getBuildConfigFile(HaxeModuleSettings settings) { public void dispose() { Collection modules = ModuleUtil.getModulesOfType(getProject(), HaxeModuleType.getInstance()); modules.forEach(HaxelibCacheManager::removeInstance); + modules.forEach(myLibraryCacheManager::removeInstance); + } + + public void moduleRemoved(Module module) { + HaxelibCacheManager.removeInstance(module); + myLibraryCacheManager.removeInstance(module); } } // end class ProjectTracker diff --git a/src/main/java/com/intellij/plugins/haxe/haxelib/HaxelibUtil.java b/src/main/java/com/intellij/plugins/haxe/haxelib/HaxelibUtil.java index f514e7ba4..8de5a4181 100644 --- a/src/main/java/com/intellij/plugins/haxe/haxelib/HaxelibUtil.java +++ b/src/main/java/com/intellij/plugins/haxe/haxelib/HaxelibUtil.java @@ -71,28 +71,30 @@ public class HaxelibUtil { * @return */ @Nullable - public static VirtualFile getLibraryBasePath(@NotNull final Sdk sdk) { - VirtualFile rootDirectory = sdk.getUserData(HaxelibRootKey); - if (null == rootDirectory) { - List output = HaxelibCommandUtils.issueHaxelibCommand(sdk, "config"); + public static VirtualFile getLibraryBasePath(@NotNull final Sdk sdk, VirtualFile workDir) { + List output = HaxelibCommandUtils.issueHaxelibCommand(sdk, workDir, "config"); for (String s : output) { if (s.isEmpty()) continue; VirtualFile file = LocalFileSystem.getInstance().findFileByPath(s); if (null != file) { - rootDirectory = file; - sdk.putUserData(HaxelibRootKey, file); - break; + return file; } - } } - return rootDirectory; + return null; } - public static VirtualFile getLibraryRoot(@NotNull Sdk sdk, @NotNull String libName, String libVersion) { + public static VirtualFile getLibraryRoot(@NotNull Sdk sdk, ModuleLibraryCache libraryCache, @NotNull String libName, String libVersion) { LocalFileSystem lfs = LocalFileSystem.getInstance(); - VirtualFile haxelibRoot = getLibraryBasePath(sdk); + VirtualFile workDirectory = libraryCache.getHaxelibWorkDirectory(); + VirtualFile haxelibRoot = libraryCache.getRepositoryPath(); + + if(haxelibRoot == null) { + + haxelibRoot = getLibraryBasePath(sdk, workDirectory); + libraryCache.setRepositoryPath(haxelibRoot); + } if(haxelibRoot == null) { log.debug("Haxe libraries base path was not found for current project sdk"); return null; @@ -152,7 +154,7 @@ public static VirtualFile getLibraryRoot(@NotNull Sdk sdk, @NotNull String libNa } // If we got here, then see what haxelib can give us. This takes >40ms on average. - List output = HaxelibCommandUtils.issueHaxelibCommand(sdk, "path", libName); + List output = HaxelibCommandUtils.issueHaxelibCommand(sdk, workDirectory, "path", libName); for (String s : output) { if (s.isEmpty()) continue; if (s.startsWith("-D")) continue; @@ -193,75 +195,6 @@ public static VirtualFile getLibraryRoot(@NotNull Sdk sdk, @NotNull String libNa } - public static Map> readInstalledLibraries(@NotNull Sdk sdk) { - - // haxelib list output looks like: - // lime-tools: 1.4.0 [1.5.6] - // The library name comes first, followed by a colon, followed by a - // list of the available versions. - - - Map> libMap = new HashMap<>(); - List listCmdOutput = HaxelibCommandUtils.issueHaxelibCommand(sdk, "list"); - if ((listCmdOutput.size() > 0) && (! listCmdOutput.get(0).contains("Unknown command"))) { - for (String line : listCmdOutput) { - String[] split = line.split(":"); - String libName = split[0]; - String libVersions = split[1]; - libVersions = libVersions.replaceAll("\\[", ""); - libVersions = libVersions.replaceAll("]", ""); - String[] versionArray = libVersions.trim().split("\s+"); - libMap.put(libName, List.copyOf(Arrays.stream(versionArray).toList())); - } - return libMap; - } - return Map.of(); - } - public static Hashtable readSelectedVersions(@NotNull Sdk sdk) { - - // haxelib list output looks like: - // lime-tools: 1.4.0 [1.5.6] - // The library name comes first, followed by a colon, followed by a - // list of the available versions. - - - Hashtable libMap = new Hashtable<>(); - List listCmdOutput = HaxelibCommandUtils.issueHaxelibCommand(sdk, "list"); - if ((listCmdOutput.size() > 0) && (!listCmdOutput.get(0).contains("Unknown command"))) { - for (String line : listCmdOutput) { - String[] split = line.split(":"); - String libName = split[0]; - String libVersions = split[1]; - String[] versionArray = libVersions.trim().split("\s+"); - for (String version : versionArray) { - if (version.startsWith("[") && version.endsWith("]")) { - version = version.replaceAll("\\[", ""); - version = version.replaceAll("]", ""); - libMap.put(libName, version); - } - } - } - return libMap; - } - return new Hashtable<>(); - } - - - - public static List getInstalledLibraryNames(@NotNull Sdk sdk) { - final List listCmdOutput = HaxelibCommandUtils.issueHaxelibCommand(sdk, "list"); - if ((listCmdOutput.size() > 0) && (! listCmdOutput.get(0).contains("Unknown command"))) { - final List installedHaxelibs = new ArrayList(); - - for (final String line : listCmdOutput) { - final String[] tokens = line.split(":"); - installedHaxelibs.add(tokens[0]); - } - return installedHaxelibs; - } - return Collections.emptyList(); - } - /** * Get the libraries for the given module. This does not include any @@ -346,12 +279,12 @@ public static HaxeLibraryList getProjectLibraries(@NotNull Project project, bool * @return The relative path, or null if the path isn't a library path. */ @Nullable - public static String getLibraryRelativeDirectory(@NotNull Sdk sdk, String path) { + public static String getLibraryRelativeDirectory(@NotNull Sdk sdk, VirtualFile workDirectory, String path) { if (null == path || path.isEmpty()) { return null; } - VirtualFile haxelibRoot = getLibraryBasePath(sdk); + VirtualFile haxelibRoot = getLibraryBasePath(sdk, workDirectory); String rootName = haxelibRoot.getPath(); String s = FileUtil.toSystemIndependentName(path); @@ -361,34 +294,21 @@ public static String getLibraryRelativeDirectory(@NotNull Sdk sdk, String path) return null; } - /** - * Given a path, determine if it is a library path and, if so, what the library name is. - * @param path file name or URL for a potential haxe library. - * @return a library name, if available. - */ - @Nullable - public static String deriveLibraryNameFromPath(@NotNull Sdk sdk, String path) { - String rel = getLibraryRelativeDirectory(sdk, path); - if (null != rel && !rel.isEmpty()) { - List libParts = FileUtil.splitPath(rel); - // First part is the library name. - return libParts.get(0); - } - return null; - } /** * Get information derivable from a library classpath. - * @param sdk + * @param libraryCache * @param path * @return */ @Nullable - public static HaxeLibraryInfo deriveLibraryInfoFromPath(@NotNull Sdk sdk, String path) { + public static HaxeLibraryInfo deriveLibraryInfoFromPath(@NotNull ModuleLibraryCache libraryCache, String path) { // TODO: Figure out how to get info from paths that are dev paths? Don't need that for current callers. + VirtualFile workDirectory = libraryCache.getHaxelibWorkDirectory(); + Sdk sdk = libraryCache.getSdk(); - String rel = getLibraryRelativeDirectory(sdk, path); + String rel = getLibraryRelativeDirectory(sdk, workDirectory , path); if (null != rel && !rel.isEmpty()) { List libParts = HaxeFileUtil.splitPath(rel); if (libParts.size() >= 2) { @@ -430,7 +350,7 @@ public static List getHaxelibDataFromXmlFile(@NotNull XmlFile xmlFi return haxeLibData; } @NotNull - public static HaxeLibraryList createHaxelibsFromHaxeLibData(@NotNull Module module, @NotNull List haxeLibData, ProjectLibraryCache libraryManager) { + public static HaxeLibraryList createHaxelibsFromHaxeLibData(@NotNull Module module, @NotNull List haxeLibData, ModuleLibraryCache libraryManager) { List haxelibNewItems = new ArrayList<>(); List missingList = new ArrayList<>(); diff --git a/src/main/java/com/intellij/plugins/haxe/haxelib/ProjectLibraryCache.java b/src/main/java/com/intellij/plugins/haxe/haxelib/ModuleLibraryCache.java similarity index 79% rename from src/main/java/com/intellij/plugins/haxe/haxelib/ProjectLibraryCache.java rename to src/main/java/com/intellij/plugins/haxe/haxelib/ModuleLibraryCache.java index 5d88d2733..471225a71 100644 --- a/src/main/java/com/intellij/plugins/haxe/haxelib/ProjectLibraryCache.java +++ b/src/main/java/com/intellij/plugins/haxe/haxelib/ModuleLibraryCache.java @@ -19,7 +19,10 @@ package com.intellij.plugins.haxe.haxelib; import com.intellij.openapi.diagnostic.LogLevel; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.ProjectUtil; import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.vfs.VirtualFile; import lombok.CustomLog; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -29,26 +32,27 @@ /** * Manages library retrieval and caching. * - * This should be instantiated once for each SDK in the project. (Projects, - * particularly those that keep separate versions of the libraries in - * source control using separate branches, are not necessarily using the - * same haxe installation.) + * This should be instantiated once for each Module. + * haxelib projects can be configured to use a local haxelib repo that differs from its SDK default. + * since modules may share SDK but have different installed libraries we have to keep a cache for each module. */ @CustomLog -public final class ProjectLibraryCache { +public final class ModuleLibraryCache { static { log.setLevel(LogLevel.DEBUG); } private final Hashtable> myCache; private final Sdk mySdk; + private final Module myModule; + private VirtualFile repositoryPath; private HaxelibInstalledIndex haxelibIndex; - public ProjectLibraryCache(@NotNull Sdk sdk) { - + public ModuleLibraryCache(@NotNull Module module, @NotNull Sdk sdk) { mySdk = sdk; + myModule = module; myCache = new Hashtable<>(); haxelibIndex = HaxelibInstalledIndex.EMPTY; @@ -56,6 +60,7 @@ public ProjectLibraryCache(@NotNull Sdk sdk) { loadInstalledLibrariesList(sdk); } public void reload() { + repositoryPath = null; myCache.clear(); haxelibIndex = HaxelibInstalledIndex.EMPTY; loadInstalledLibrariesList(mySdk); @@ -66,8 +71,8 @@ private void loadInstalledLibrariesList(@NotNull Sdk sdk) { log.warn("Unable to load install library list, invalid SDK paths"); return; } - - haxelibIndex = HaxelibInstalledIndex.fetchFromHaxelib(sdk); + VirtualFile workDir = getHaxelibWorkDirectory(); + haxelibIndex = HaxelibInstalledIndex.fetchFromHaxelib(sdk, workDir); for (String libName : haxelibIndex.getInstalledLibraries()) { Set versions = haxelibIndex.getInstalledVersions(libName); @@ -81,6 +86,10 @@ private void loadInstalledLibrariesList(@NotNull Sdk sdk) { } } + @Nullable + public VirtualFile getHaxelibWorkDirectory() { + return ProjectUtil.guessModuleDir(myModule); + } @Nullable @@ -121,7 +130,8 @@ public Sdk getSdk() { private Collection retrieveKnownLibraries() { // If we don't have the list, then load it. if (haxelibIndex == HaxelibInstalledIndex.EMPTY) { - haxelibIndex = HaxelibInstalledIndex.fetchFromHaxelib(mySdk); + VirtualFile workDir = getHaxelibWorkDirectory(); + haxelibIndex = HaxelibInstalledIndex.fetchFromHaxelib(mySdk, workDir); } return haxelibIndex.getInstalledLibraries(); } @@ -148,11 +158,18 @@ public HaxeLibrary getLibraryByPath(String path) { // Looking up a library in the cache resolves to a serial search. Instead, // parse the path for a library name and version, and then look it up. - HaxeLibraryInfo info = HaxelibUtil.deriveLibraryInfoFromPath(mySdk, path); + HaxeLibraryInfo info = HaxelibUtil.deriveLibraryInfoFromPath(this, path); if (null != info) { return getLibrary(info.name, info.semver); } return null; } + public VirtualFile getRepositoryPath() { + return repositoryPath; + } + + public void setRepositoryPath(VirtualFile root) { + repositoryPath = root; + } } diff --git a/src/main/java/com/intellij/plugins/haxe/haxelib/ProjectLibraryCacheManager.java b/src/main/java/com/intellij/plugins/haxe/haxelib/ProjectLibraryCacheManager.java index a3a88cfac..ad83deaaf 100644 --- a/src/main/java/com/intellij/plugins/haxe/haxelib/ProjectLibraryCacheManager.java +++ b/src/main/java/com/intellij/plugins/haxe/haxelib/ProjectLibraryCacheManager.java @@ -48,10 +48,9 @@ public class ProjectLibraryCacheManager { } - final SdkCache mySdkCache; + final Hashtable myCacheMap = new Hashtable<>(); public ProjectLibraryCacheManager() { - mySdkCache = new SdkCache(); } /** @@ -63,125 +62,47 @@ public ProjectLibraryCacheManager() { * @return a library manager for the given module. */ @NotNull - public ProjectLibraryCache getLibraryManager(@NotNull Module module) { + public ModuleLibraryCache getLibraryManager(@NotNull Module module) { Sdk sdk = HaxelibSdkUtils.lookupSdk(module); - return getLibraryCache(sdk); + if(myCacheMap.containsKey(module)) { + return myCacheMap.get(module).getLibraryCache(); + }else { + SdkEntry entry = new SdkEntry(module, sdk); + myCacheMap.put(module, entry); + return entry.getLibraryCache(); + } } - /** - * Get the library manager associated with the given SDK. There is - * only one per project with the given name (e.g. modules that specify - * the same SDK will get the same library manager object). Therefore, - * if all modules specify the same SDK it is functionally identical to - * inheriting the project SDK. - * - * @param sdk - SDK to look up libraries for. - * @return a library manager for the given SDK. - */ - @NotNull - public ProjectLibraryCache getLibraryCache(@NotNull Sdk sdk) { - SdkEntry entry = mySdkCache.get(sdk.getName()); - if (null == entry) { - // Not in the cache? Put it there. - entry = new SdkEntry(sdk); - mySdkCache.add(entry); - } - return entry.getLibraryCache(); + public void clear() { + myCacheMap.clear(); + } + + public void removeInstance(Module module) { + myCacheMap.remove(module); } + /** * Cache entry for the SDK table. */ static final class SdkEntry { - final Sdk mySdk; - final ProjectLibraryCache myMgr; + final Module module; + final ModuleLibraryCache myMgr; - public SdkEntry(@NotNull Sdk sdk) { - mySdk = sdk; - myMgr = new ProjectLibraryCache(sdk); + public SdkEntry(@NotNull Module module, @NotNull Sdk sdk) { + this.module = module; + myMgr = new ModuleLibraryCache(module, sdk); } @NotNull public String getName() { - return mySdk.getName(); + return module.getName(); } @NotNull - public ProjectLibraryCache getLibraryCache() { + public ModuleLibraryCache getLibraryCache() { return myMgr; } - public boolean nameEquals(@NotNull SdkEntry entry) { - return getName().equals(entry.getName()); - } - - public boolean nameEquals(@NotNull String name) { - return getName().equals(name); - } - } - - /** - * Cache of library managers per SDK. - */ - final class SdkCache { - // Optimize the common case where we only have one... - SdkEntry cacheOfOne = null; - - Hashtable myCache; - - public SdkCache() { - } - - /** - * Lazy initialization. - */ - private void initCache() { - myCache = new Hashtable(); - } - - /** - * Add a library manager to the cache. If a library manager of the same - * name already exists, the old one will be kept and the new ignored. - * - * @param entry An SdkEntry object - */ - public void add(@NotNull SdkEntry entry) { - if (null == myCache) { - if (null == cacheOfOne ) { - cacheOfOne = entry; - } else if (! cacheOfOne.nameEquals(entry)) { // Don't need to add another of the same name. - initCache(); - add(entry); - add(cacheOfOne); - cacheOfOne = null; - } - } else { - if (! myCache.containsKey(entry.getName())) { // Don't replace a full cache with an empty one. - SdkEntry oldEntry = myCache.put(entry.getName(), entry); - if (null != oldEntry) { - log.warn("Duplicating cached data for entry " + entry.getName()); - } - } - } - } - - public void clear() { - cacheOfOne = null; - if (null != myCache) { - myCache.clear(); - } - } - - @Nullable - public SdkEntry get(@NotNull String name) { - if (null != cacheOfOne && cacheOfOne.nameEquals(name)) { - return cacheOfOne; - } - if (null != myCache) { - return myCache.get(name); - } - return null; - } } - } diff --git a/src/main/java/com/intellij/plugins/haxe/ide/projectStructure/HaxeProjectImportBuilder.java b/src/main/java/com/intellij/plugins/haxe/ide/projectStructure/HaxeProjectImportBuilder.java index 6c4763874..672b29fa0 100644 --- a/src/main/java/com/intellij/plugins/haxe/ide/projectStructure/HaxeProjectImportBuilder.java +++ b/src/main/java/com/intellij/plugins/haxe/ide/projectStructure/HaxeProjectImportBuilder.java @@ -18,6 +18,7 @@ import com.intellij.openapi.ui.MessageConstants; import com.intellij.openapi.ui.ex.MessagesEx; import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.packaging.artifacts.ModifiableArtifactModel; import com.intellij.plugins.haxe.HaxeBundle; import com.intellij.plugins.haxe.config.HaxeConfiguration; @@ -127,5 +128,9 @@ private static void configureProjectSettings(HaxeProjectData haxeProjectData, Ha private static void configureContentRoots(HaxeProjectData haxeProjectData, ModifiableRootModel rootModel) { ContentEntry contentRoot = rootModel.addContentEntry(haxeProjectData.getProjectRoot()); haxeProjectData.getSourcePaths().forEach(source -> contentRoot.addSourceFolder(source, false)); + VirtualFile localHaxelibRepo = haxeProjectData.getProjectRoot().findChild(".haxelib"); + if(localHaxelibRepo != null && localHaxelibRepo.exists()) { + contentRoot.addExcludeFolder(localHaxelibRepo); + } } } diff --git a/src/main/java/com/intellij/plugins/haxe/ide/projectStructure/detection/HaxeProjectConfigurationUpdater.java b/src/main/java/com/intellij/plugins/haxe/ide/projectStructure/detection/HaxeProjectConfigurationUpdater.java index ea315d741..965bd8942 100644 --- a/src/main/java/com/intellij/plugins/haxe/ide/projectStructure/detection/HaxeProjectConfigurationUpdater.java +++ b/src/main/java/com/intellij/plugins/haxe/ide/projectStructure/detection/HaxeProjectConfigurationUpdater.java @@ -21,7 +21,9 @@ import com.intellij.execution.configurations.ConfigurationFactory; import com.intellij.ide.util.projectWizard.importSources.impl.ProjectFromSourcesBuilderImpl; import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleUtil; import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectUtil; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.ModifiableModelsProvider; import com.intellij.openapi.roots.ModifiableRootModel; @@ -38,6 +40,7 @@ import com.intellij.plugins.haxe.haxelib.HaxelibSdkUtils; import com.intellij.plugins.haxe.ide.library.HaxeLibraryType; import com.intellij.plugins.haxe.ide.module.HaxeModuleSettings; +import com.intellij.plugins.haxe.ide.module.HaxeModuleType; import com.intellij.plugins.haxe.ide.projectStructure.HXMLData; import com.intellij.plugins.haxe.runner.HaxeApplicationConfiguration; import com.intellij.plugins.haxe.runner.HaxeRunConfigurationType; @@ -47,6 +50,7 @@ import java.io.File; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Set; @@ -61,8 +65,10 @@ public HaxeProjectConfigurationUpdater(String projectRoot) { @Override public void updateProject(@NotNull Project project, @NotNull ModifiableModelsProvider modelsProvider, @NotNull ModulesProvider modulesProvider) { + if(myLibraries != null && !myLibraries.isEmpty()) { - List libraries = collectLibraries(project); + Module rootModule = getRootModule(modelsProvider, modulesProvider); + List libraries = collectLibraries(rootModule); if(!libraries.isEmpty()) { setupLibraries(project, modelsProvider, modulesProvider, libraries); } @@ -139,11 +145,12 @@ private void setupHxmlRunConfigurations(Module module) { } } - private List collectLibraries(Project project) { + private List collectLibraries(Module module) { List result = new ArrayList<>(); - Sdk sdk = HaxelibSdkUtils.lookupSdk(project); + Sdk sdk = HaxelibSdkUtils.lookupSdk(module); String[] libNames = myLibraries.toArray(new String[0]); - Set cpList = HaxelibClasspathUtils.getHaxelibLibrariesClasspaths(sdk, libNames); + VirtualFile workDir = ProjectUtil.guessModuleDir(module); + Set cpList = HaxelibClasspathUtils.getHaxelibLibrariesClasspaths(sdk, workDir, libNames); for(String cp:cpList) { VirtualFile current = LocalFileSystem.getInstance().findFileByPath(cp); //"haxelib path" returns something like "/path/to/repo/libname/1,0,0/src"