diff --git a/io.sloeber.core/src/io/sloeber/arduinoFramework/api/LibraryManager.java b/io.sloeber.core/src/io/sloeber/arduinoFramework/api/LibraryManager.java index bac7c518..455cffb2 100644 --- a/io.sloeber.core/src/io/sloeber/arduinoFramework/api/LibraryManager.java +++ b/io.sloeber.core/src/io/sloeber/arduinoFramework/api/LibraryManager.java @@ -38,7 +38,7 @@ import io.sloeber.core.common.InstancePreferences; import io.sloeber.core.core.DefaultInstallHandler; import io.sloeber.core.internal.ArduinoHardwareLibrary; -import io.sloeber.core.internal.ArduinoPrivateLibraryVersion; +import io.sloeber.core.internal.ArduinoPrivateHardwareLibraryVersion; import io.sloeber.core.internal.Example; import io.sloeber.core.tools.FileModifiers; import io.sloeber.core.tools.PackageManager; @@ -87,6 +87,10 @@ public static String getPrivateLibraryPathsString() { return InstancePreferences.getPrivateLibraryPathsString(); } + public static String[] getPrivateLibraryPaths() { + return InstancePreferences.getPrivateLibraryPaths(); + } + public static void setPrivateLibraryPaths(String[] libraryPaths) { InstancePreferences.setPrivateLibraryPaths(libraryPaths); @@ -335,6 +339,17 @@ public static IStatus updateLibraries(Set toUnInstallLib return status; } + /** + * A convenience (and downward compatibility method of + * getLibrariesAll(BoardDescription boardDescriptor, true) { + * + * @param confDesc can be null + * @return A map of FQN IArduinoLibraryVersion + */ + public static TreeMap getLibrariesAll(BoardDescription boardDescriptor) { + return getLibrariesAll( boardDescriptor, true); + } + /** * Given a sloeber configuration provide all the libraries that can be used by * this sketch This boils down to all libraries maintained by the Library @@ -342,36 +357,41 @@ public static IStatus updateLibraries(Set toUnInstallLib * provided by the personal libraries * * @param confDesc can be null - * @return + * @return if keyIsFQN is true: A map of FQN IArduinoLibraryVersion + * if keyIsFQN is false: A map of location IArduinoLibraryVersion */ - public static TreeMap getLibrariesAll(BoardDescription boardDescriptor) { + public static TreeMap getLibrariesAll(BoardDescription boardDescriptor, boolean keyIsFQN) { TreeMap libraries = new TreeMap<>(); - libraries.putAll(getLibrariesdManaged()); - libraries.putAll(getLibrariesPrivate()); + libraries.putAll(getLibrariesdManaged(keyIsFQN)); + libraries.putAll(getLibrariesPrivate(keyIsFQN)); if (boardDescriptor != null) { - libraries.putAll(getLibrariesHarware(boardDescriptor)); + libraries.putAll(getLibrariesHarware(boardDescriptor,keyIsFQN)); } return libraries; } - private static Map getLibrariesdManaged() { + private static Map getLibrariesdManaged(boolean keyIsFQN) { Map ret = new HashMap<>(); for (IArduinoLibraryIndex libindex : libraryIndices) { for (IArduinoLibrary curLib : libindex.getLibraries()) { IArduinoLibraryVersion instVersion = curLib.getInstalledVersion(); if (instVersion != null) { - ret.put(instVersion.getFQN().toPortableString(), instVersion); + if (keyIsFQN) { + ret.put(instVersion.getFQN().toPortableString(), instVersion); + } else { + ret.put(instVersion.getInstallPath().toPortableString(), instVersion); + } } } } return ret; } - private static Map getLibrariesPrivate() { + private static Map getLibrariesPrivate(boolean keyIsFQN) { Map ret = new HashMap<>(); String privateLibPaths[] = InstancePreferences.getPrivateLibraryPaths(); for (String curLibPath : privateLibPaths) { - ret.putAll(getLibrariesFromFolder(new Path(curLibPath), 2, false,true)); + ret.putAll(getLibrariesFromFolder(new Path(curLibPath), 2, false,true,keyIsFQN)); } return ret; @@ -381,12 +401,13 @@ private static Map getLibrariesPrivate() { * for a given folder return all subfolders * * @param ipath the folder you want the subfolders off + * @param keyIsFQN * @return The subfolders of the ipath folder. May contain empty values. This * method returns a key value pair of key equals foldername and value * equals full path. */ private static Map getLibrariesFromFolder(IPath ipath, int depth, - boolean isHardwareLib,boolean isPrivate) { + boolean isHardwareLib,boolean isPrivate, boolean keyIsFQN) { if (ConfigurationPreferences.getInstallationPathLibraries().isPrefixOf(ipath)) { System.err.println("The method findAllPrivateLibs should not be called on Library manager installed libs"); //$NON-NLS-1$ } @@ -405,13 +426,9 @@ private static Map getLibrariesFromFolder(IPath } String fileExt = (new Path(curChild)).getFileExtension(); if (LIBRARY_INDICATION_FILES.contains(curChild) || CODE_EXTENSIONS.contains(fileExt)) { - if (isHardwareLib) { - IArduinoLibraryVersion retVersion = new ArduinoHardwareLibrary(ipath); - ret.put(retVersion.getFQN().toPortableString(), retVersion); - } else { - IArduinoLibraryVersion retVersion = new ArduinoPrivateLibraryVersion(ipath); - ret.put(retVersion.getFQN().toPortableString(), retVersion); - } + IArduinoLibraryVersion retVersion = isHardwareLib?new ArduinoHardwareLibrary(ipath):new ArduinoPrivateHardwareLibraryVersion(ipath); + String key=keyIsFQN?retVersion.getFQN().toPortableString():retVersion.getInstallPath().toPortableString(); + ret.put(key, retVersion); return ret; } @@ -425,7 +442,7 @@ private static Map getLibrariesFromFolder(IPath IPath LibPath = ipath.append(curFolder); File LibPathFile = LibPath.toFile(); if (LibPathFile.isDirectory() && !LibPathFile.isHidden()) { - ret.putAll(getLibrariesFromFolder(LibPath, depth - 1, isHardwareLib,isPrivate)); + ret.putAll(getLibrariesFromFolder(LibPath, depth - 1, isHardwareLib,isPrivate,keyIsFQN)); } } return ret; @@ -435,21 +452,22 @@ private static Map getLibrariesFromFolder(IPath * Searches all the hardware dependent libraries of a project. If this is a * board referencing a core then the libraries of the referenced core are added * as well + * @param keyIsFQN * * @param project the project to find all hardware libraries for * @return all the library folder names. May contain empty values. */ - public static Map getLibrariesHarware(BoardDescription boardDescriptor) { + public static Map getLibrariesHarware(BoardDescription boardDescriptor, boolean keyIsFQN) { Map ret = new HashMap<>(); // first add the referenced IPath libPath = boardDescriptor.getReferencedCoreLibraryPath(); if (libPath != null) { - ret.putAll(getLibrariesFromFolder(libPath, 1, true,boardDescriptor.isPrivate())); + ret.putAll(getLibrariesFromFolder(libPath, 1, true,boardDescriptor.isPrivate(),keyIsFQN)); } // then add the referencing libPath = boardDescriptor.getReferencingLibraryPath(); if (libPath != null) { - ret.putAll(getLibrariesFromFolder(libPath, 1, true,boardDescriptor.isPrivate())); + ret.putAll(getLibrariesFromFolder(libPath, 1, true,boardDescriptor.isPrivate(),keyIsFQN)); } return ret; } @@ -458,17 +476,39 @@ public static IArduinoLibraryVersion getLibraryVersionFromLocation(IFolder libFo if (boardDescriptor != null) { IPath libPath=boardDescriptor.getReferencedCoreLibraryPath(); if(libPath!=null && libPath.isPrefixOf(libFolder.getLocation())) { - String FQNLibName=ArduinoHardwareLibrary.calculateFQN(libFolder.getName()).toString(); - return getLibrariesHarware(boardDescriptor).get(FQNLibName); + return getLibrariesHarware(boardDescriptor,false).get(libFolder.getLocation().toPortableString()); } } if(ConfigurationPreferences.getInstallationPathLibraries().isPrefixOf(libFolder.getLocation())) { - String FQNLibName= ArduinoLibraryVersion.calculateFQN(libFolder.getName()).toString(); - return getLibrariesdManaged().get(FQNLibName); + return getLibrariesdManaged(false).get(libFolder.getLocation().toPortableString()); } - return getLibrariesPrivate().get(libFolder.getName()); + return getLibrariesPrivate(false).get(libFolder.getLocation().toPortableString()); + } + + public static IArduinoLibraryVersion getLibraryVersionFromFQN(String FQNLibName, BoardDescription boardDescriptor) { + String[] fqnParts = FQNLibName.split(SLACH); + if (fqnParts.length < 3) { + return null; + } + if (!SLOEBER_LIBRARY_FQN.equals(fqnParts[0])) { + // this is not a library + return null; + } + if (MANAGED.equals(fqnParts[1])) { + if (BOARD.equals(fqnParts[2])) { + if (boardDescriptor == null) { + return null; + } + return getLibrariesHarware(boardDescriptor,true).get(FQNLibName); + } + return getLibrariesdManaged(true).get(FQNLibName); + } + if (PRIVATE.equals(fqnParts[1])) { + return getLibrariesPrivate(true).get(FQNLibName); + } + return null; } /** diff --git a/io.sloeber.core/src/io/sloeber/core/api/SloeberProject.java b/io.sloeber.core/src/io/sloeber/core/api/SloeberProject.java index 29e3305a..5033918e 100644 --- a/io.sloeber.core/src/io/sloeber/core/api/SloeberProject.java +++ b/io.sloeber.core/src/io/sloeber/core/api/SloeberProject.java @@ -51,7 +51,7 @@ import io.sloeber.core.Messages; import io.sloeber.core.api.CompileDescription.SizeCommands; import io.sloeber.core.internal.ArduinoHardwareLibrary; -import io.sloeber.core.internal.ArduinoPrivateLibraryVersion; +import io.sloeber.core.internal.ArduinoPrivateHardwareLibraryVersion; import io.sloeber.core.internal.SloeberConfiguration; import io.sloeber.core.listeners.IndexerController; import io.sloeber.core.natures.SloeberNature; @@ -241,7 +241,7 @@ public void run(IProgressMonitor internalMonitor) throws CoreException { continue; } - IPath privateLibFQN = ArduinoPrivateLibraryVersion.calculateFQN(curLibName); + IPath privateLibFQN = ArduinoPrivateHardwareLibraryVersion.calculateFQN(curLibName); foundLib = availableLibs.get(privateLibFQN.toString()); if (foundLib != null) { toInstallLibs.add(foundLib); diff --git a/io.sloeber.core/src/io/sloeber/core/internal/ArduinoPrivateLibraryVersion.java b/io.sloeber.core/src/io/sloeber/core/internal/ArduinoPrivateHardwareLibraryVersion.java similarity index 92% rename from io.sloeber.core/src/io/sloeber/core/internal/ArduinoPrivateLibraryVersion.java rename to io.sloeber.core/src/io/sloeber/core/internal/ArduinoPrivateHardwareLibraryVersion.java index 0c649e65..dc7a4099 100644 --- a/io.sloeber.core/src/io/sloeber/core/internal/ArduinoPrivateLibraryVersion.java +++ b/io.sloeber.core/src/io/sloeber/core/internal/ArduinoPrivateHardwareLibraryVersion.java @@ -12,18 +12,18 @@ import io.sloeber.core.api.VersionNumber; import io.sloeber.core.common.InstancePreferences; -public class ArduinoPrivateLibraryVersion implements IArduinoLibraryVersion { +public class ArduinoPrivateHardwareLibraryVersion implements IArduinoLibraryVersion { private IPath myInstallPath; private String myName; private IPath myFQN; - public ArduinoPrivateLibraryVersion(IPath installPath) { + public ArduinoPrivateHardwareLibraryVersion(IPath installPath) { myInstallPath = installPath; myName = myInstallPath.lastSegment(); myFQN= calculateFQN(getName()); } - public ArduinoPrivateLibraryVersion(String curSaveString) { + public ArduinoPrivateHardwareLibraryVersion(String curSaveString) { String[] parts=curSaveString.split(SEMI_COLON); myName=parts[parts.length-1]; myFQN= calculateFQN(getName()); diff --git a/io.sloeber.core/src/io/sloeber/core/internal/SloeberConfiguration.java b/io.sloeber.core/src/io/sloeber/core/internal/SloeberConfiguration.java index c883f3c1..8e76dc6e 100644 --- a/io.sloeber.core/src/io/sloeber/core/internal/SloeberConfiguration.java +++ b/io.sloeber.core/src/io/sloeber/core/internal/SloeberConfiguration.java @@ -611,7 +611,7 @@ private void upDateHardwareLibraries() { } } if (!hardwareLibsFQN.isEmpty()) { - Map boardLibs = LibraryManager.getLibrariesHarware(boardDesc); + Map boardLibs = LibraryManager.getLibrariesHarware(boardDesc,true); for (IPath curReplaceLibFQN : hardwareLibsFQN) { IArduinoLibraryVersion newLib = boardLibs.get(curReplaceLibFQN.toPortableString()); if (newLib != null) { diff --git a/io.sloeber.tests/src/io/sloeber/core/BuildTests.java b/io.sloeber.tests/src/io/sloeber/core/BuildTests.java index ba0f0754..7f022d57 100644 --- a/io.sloeber.tests/src/io/sloeber/core/BuildTests.java +++ b/io.sloeber.tests/src/io/sloeber/core/BuildTests.java @@ -2,7 +2,7 @@ - +import static io.sloeber.core.api.Const.*; import java.io.File; import java.util.Arrays; import java.util.Collection; @@ -15,6 +15,8 @@ import java.util.TreeMap; import java.util.stream.Stream; import java.net.URI; +import java.nio.file.Files; +import java.nio.file.StandardOpenOption; import org.apache.commons.io.FileUtils; @@ -25,8 +27,10 @@ import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.internal.core.pdom.indexer.IndexerPreferences; import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.IncrementalProjectBuilder; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; @@ -801,4 +805,104 @@ public void NightlyBoardPatron(String name, MCUBoard boardID, Example example, C } + + /** + * Use private lib from the workspace. + * Close project + * open project + * Is the lib still there (as does project still build) + * + * @throws Exception + */ + @Test + public void issue1723() throws Exception { + final String projectName = "private_lib"; + final String privateLibFolderName = "an_private_lib"; + final String privateLibName = "a_private_lib"; + final String libHeaderContent=("int aFunction();")+System.lineSeparator(); + String libCodeContent=("#include \""+privateLibName+".h\"")+System.lineSeparator(); + libCodeContent=libCodeContent+("int aFunction(){")+System.lineSeparator(); + libCodeContent=libCodeContent+("}")+System.lineSeparator(); + String libRefContent=("#include \""+privateLibName+".h\"")+System.lineSeparator(); + libRefContent=libRefContent+("int aRefFunction(){")+System.lineSeparator(); + libRefContent=libRefContent+("aFunction();")+System.lineSeparator(); + libRefContent=libRefContent+("}")+System.lineSeparator(); + + + //create a basic arduino project + BoardDescription unoBoardid = Arduino.uno().getBoardDescriptor(); + IProject theTestProject = null; + + IPath templateFolder = Shared.getTemplateFolder("CreateAndCompileTest"); + CodeDescription codeDescriptor = CodeDescription.createCustomTemplate(templateFolder); + theTestProject = SloeberProject.createArduinoProject(projectName, null, unoBoardid, codeDescriptor, + new CompileDescription(), new NullProgressMonitor()); + Shared.waitForIndexer(theTestProject); + + //create a private library project + final IWorkspace workspace = ResourcesPlugin.getWorkspace(); + IWorkspaceRoot root = workspace.getRoot(); + IProject theLibProject= root.getProject("PrivateLibs"); + theLibProject.create(new NullProgressMonitor()); + theLibProject.open(new NullProgressMonitor()); + IFolder libFolder = theLibProject.getFolder(privateLibFolderName); + libFolder.create(true, true, new NullProgressMonitor()); + IFile libHeaderFile=libFolder.getFile(privateLibName+".h"); + IFile libSourceFile=libFolder.getFile(privateLibName+".cpp"); + + Files.write(libHeaderFile.getLocation().toPath(), libHeaderContent.getBytes(), StandardOpenOption.TRUNCATE_EXISTING, + StandardOpenOption.CREATE); + Files.write(libSourceFile.getLocation().toPath(), libCodeContent.getBytes(), StandardOpenOption.TRUNCATE_EXISTING, + StandardOpenOption.CREATE); + + + //build project (should work) + theTestProject.build(IncrementalProjectBuilder.FULL_BUILD, new NullProgressMonitor()); + assertNull(Shared.hasBuildErrors(theTestProject),"Created Project does not build."); + + + //Add code to project that uses private lib + IFolder srcFolder = theTestProject.getFolder("src"); + IFile referingFile=srcFolder.getFile("privateLibUser.cpp"); + Files.write(referingFile.getLocation().toPath(), libRefContent.getBytes(), StandardOpenOption.TRUNCATE_EXISTING, + StandardOpenOption.CREATE); + + //build project (should fail) + theTestProject.build(IncrementalProjectBuilder.FULL_BUILD, new NullProgressMonitor()); + assertNotNull(Shared.hasBuildErrors(theTestProject),"Lib should be missing; build should fail."); + + + //add private libs project to the sloeber preferences private libs + List privateLibList= new LinkedList<>(); + privateLibList.add(theLibProject.getLocation().toOSString()); + privateLibList.addAll( Arrays.asList( LibraryManager.getPrivateLibraryPaths())); + LibraryManager.setPrivateLibraryPaths(privateLibList.toArray(new String[privateLibList.size()])); + + + + //add the private lib to the project + IArduinoLibraryVersion privateArduinoLib=LibraryManager.getLibraryVersionFromFQN(SLOEBER_LIBRARY_FQN+SLACH+PRIVATE+SLACH+libFolder.getName(), null); + Collection myPrivateLibs =new LinkedList<>(); + myPrivateLibs.add(privateArduinoLib); + + ISloeberConfiguration sloeberConf=ISloeberConfiguration.getActiveConfig(theTestProject, true); + sloeberConf.addLibraries(myPrivateLibs); + + //build project (should work) + theTestProject.build(IncrementalProjectBuilder.FULL_BUILD, new NullProgressMonitor()); + assertNull(Shared.hasBuildErrors(theTestProject),"lib added build should succeed"); + + //open and close the project to clear the cache + theTestProject.close(null); + // just wait a while + Thread.sleep(1000); + + theTestProject.open(new NullProgressMonitor()); + + //There should be 1 lib in the project + sloeberConf=ISloeberConfiguration.getActiveConfig(theTestProject, true); + Map usedLibs=sloeberConf.getUsedLibraries(); + assertEquals(1,usedLibs.size(),"Private Lib not found"); + + } }