package io.sloeber.core.tools;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.index.IIndexFile;
import org.eclipse.cdt.core.index.IIndexInclude;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.cdt.core.settings.model.ICProjectDescriptionManager;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import io.sloeber.core.common.Common;
import io.sloeber.core.common.ConfigurationPreferences;
import io.sloeber.core.common.Const;
import io.sloeber.core.common.InstancePreferences;
public class Libraries {
/**
* for a given folder return all subfolders
*
* @param ipath
* the folder you want the subfolders off
* @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<String, IPath> findAllSubFolders(IPath ipath) {
String[] children = ipath.toFile().list();
Map<String, IPath> ret = new HashMap<>();
if (children == null) {
// Either dir does not exist or is not a directory
} else {
for (String curFolder : children) {
// Get filename of file or directory
IPath LibPath = ipath.append(curFolder);
File LibPathFile = LibPath.toFile();
if (LibPathFile.isDirectory() && !LibPathFile.isHidden()) {
ret.put(curFolder, LibPath);
}
}
}
return ret;
}
/**
* 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 project
* the project to find all hardware libraries for
* @return all the library folder names. May contain empty values. This
* method does not return the full path only the leaves.
*/
private static Map<String, IPath> findAllHarwareLibraries(ICConfigurationDescription confdesc) {
String platformFile = Common.getBuildEnvironmentVariable(confdesc, Const.ENV_KEY_JANTJE_PLATFORM_FILE,
new String());
IPath LibraryFolder = new Path(platformFile).removeLastSegments(1).append(Const.LIBRARY_PATH_SUFFIX);
Map<String, IPath> ret = findAllSubFolders(LibraryFolder);
String platform = Common.getBuildEnvironmentVariable(confdesc, Const.ENV_KEY_JANTJE_CORE_REFERENCED_PLATFORM,
null);
if (platform != null) {
LibraryFolder = new Path(platformFile).append(Const.LIBRARY_PATH_SUFFIX);
ret.putAll(findAllSubFolders(LibraryFolder));
}
return ret;
}
public static Map<String, IPath> findAllPrivateLibraries() {
Map<String, IPath> ret = new HashMap<>();
String privateLibPaths[] = InstancePreferences.getPrivateLibraryPaths();
for (String curLibPath : privateLibPaths) {
ret.putAll(findAllSubFolders(new Path(curLibPath)));
}
return ret;
}
public static Map<String, IPath> findAllArduinoManagerLibraries() {
Map<String, IPath> ret = new HashMap<>();
IPath CommonLibLocation = ConfigurationPreferences.getInstallationPathLibraries();
if (CommonLibLocation.toFile().exists()) {
String[] Libs = CommonLibLocation.toFile().list();
if (Libs == null) {
// Either dir does not exist or is not a directory
} else {
java.util.Arrays.sort(Libs, String.CASE_INSENSITIVE_ORDER);
for (String curLib : Libs) {
IPath Lib_root = CommonLibLocation.append(curLib);
String[] versions = Lib_root.toFile().list();
if (versions != null) {
if (versions.length == 1) {// There should only be 1
// version of a lib
ret.put(curLib, Lib_root.append(versions[0]));
} else {// If there is more than 1 take the latest and
// drop a warning
int highestVersion = Version.getHighestVersionn(versions);
ret.put(curLib, Lib_root.append(versions[highestVersion]));
Common.log(new Status(IStatus.WARNING, Const.CORE_PLUGIN_ID,
Messages.MultipleVersionsOfLib.replace("${LIB}", curLib))); //$NON-NLS-1$
}
}
}
}
}
return ret;
}
/**
* Removes a set of libraries from a project
*
* @param project
* the project from which to remove libraries
* @param confdesc
* the configuration from which to remove libraries
* @param libraries
* set of libraries to remove
*/
public static void removeLibrariesFromProject(IProject project, ICConfigurationDescription confdesc,
Set<String> libraries) {
for (String CurItem : libraries) {
try {
final IFolder folderHandle = project.getFolder(Const.WORKSPACE_LIB_FOLDER + CurItem);
folderHandle.delete(true, null);
} catch (CoreException e) {
Common.log(new Status(IStatus.ERROR, Const.CORE_PLUGIN_ID, Messages.failed_to_remove_lib, e));
}
}
Helpers.removeInvalidIncludeFolders(confdesc);
}
public static Map<String, IPath> getAllInstalledLibraries(ICConfigurationDescription confdesc) {
TreeMap<String, IPath> libraries = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
// lib folder name
libraries.putAll(findAllArduinoManagerLibraries());
libraries.putAll(findAllPrivateLibraries());
libraries.putAll(findAllHarwareLibraries(confdesc));
return libraries;
}
public static void addLibrariesToProject(IProject project, ICConfigurationDescription confdesc,
Set<String> librariesToAdd) {
Map<String, IPath> libraries = getAllInstalledLibraries(confdesc);
libraries.keySet().retainAll(librariesToAdd);
addLibrariesToProject(project, confdesc, libraries);
}
private static void addLibrariesToProject(IProject project, ICConfigurationDescription confdesc,
Map<String, IPath> libraries) {
for (Entry<String, IPath> CurItem : libraries.entrySet()) {
try {
Helpers.addCodeFolder(project, CurItem.getValue(), Const.WORKSPACE_LIB_FOLDER + CurItem.getKey(),
confdesc);
} catch (CoreException e) {
Common.log(new Status(IStatus.ERROR, Const.CORE_PLUGIN_ID, Messages.import_lib_failed, e));
}
}
}
// public static void removeLibrariesFromProject(Set<String> libraries) {
//
// }
public static Set<String> getAllLibrariesFromProject(IProject project) {
IFolder link = project.getFolder(Const.WORKSPACE_LIB_FOLDER);
Set<String> ret = new TreeSet<>();
try {
if (link.exists()) {
for (IResource curResource : link.members()) {
ret.add(curResource.getName());
}
}
} catch (CoreException e) {
// ignore
e.printStackTrace();
}
return ret;
}
public static void reAttachLibrariesToProject(IProject project) {
Set<String> AllLibrariesOriginallyUsed = getAllLibrariesFromProject(project);
ICProjectDescriptionManager mngr = CoreModel.getDefault().getProjectDescriptionManager();
ICProjectDescription projectDescription = mngr.getProjectDescription(project, true);
ICConfigurationDescription configurationDescriptions[] = projectDescription.getConfigurations();
for (ICConfigurationDescription CurItem : configurationDescriptions) {
addLibrariesToProject(project, CurItem, AllLibrariesOriginallyUsed);
}
try {
mngr.setProjectDescription(project, projectDescription, true, null);
} catch (CoreException e) {
e.printStackTrace();
}
}
public static void reAttachLibrariesToProject(ICConfigurationDescription confdesc) {
Set<String> AllLibrariesOriginallyUsed = getAllLibrariesFromProject(
confdesc.getProjectDescription().getProject());
addLibrariesToProject(confdesc.getProjectDescription().getProject(), confdesc, AllLibrariesOriginallyUsed);
}
public static void addLibrariesToProject(IProject project, Set<String> selectedLibraries) {
ICProjectDescriptionManager mngr = CoreModel.getDefault().getProjectDescriptionManager();
ICProjectDescription projectDescription = mngr.getProjectDescription(project, true);
ICConfigurationDescription configurationDescription = projectDescription.getActiveConfiguration();
addLibrariesToProject(project, configurationDescription, selectedLibraries);
try {
mngr.setProjectDescription(project, projectDescription, true, null);
} catch (CoreException e) {
e.printStackTrace();
}
}
/**
* Removes a set of libraries from a project in each project configuration
*
* @param project
* the project from which to remove libraries
* @param libraries
* set of libraries to remove
*/
public static void removeLibrariesFromProject(IProject project, Set<String> selectedLibraries) {
ICProjectDescriptionManager mngr = CoreModel.getDefault().getProjectDescriptionManager();
ICProjectDescription projectDescription = mngr.getProjectDescription(project, true);
ICConfigurationDescription configurationDescriptions[] = projectDescription.getConfigurations();
for (ICConfigurationDescription CurItem : configurationDescriptions) {
removeLibrariesFromProject(project, CurItem, selectedLibraries);
}
try {
mngr.setProjectDescription(project, projectDescription, true, null);
} catch (CoreException e) {
e.printStackTrace();
}
}
private static Set<String> getUnresolvedProjectIncludes(IProject iProject) {
Set<String> ret = new TreeSet<>();
ICProject tt = CoreModel.getDefault().create(iProject);
IIndex index = null;
try {
index = CCorePlugin.getIndexManager().getIndex(tt);
index.acquireReadLock();
try {
IIndexFile allFiles[] = index.getFilesWithUnresolvedIncludes();
for (IIndexFile curUnesolvedIncludeFile : allFiles) {
IIndexInclude includes[] = curUnesolvedIncludeFile.getIncludes();
for (IIndexInclude curinclude : includes) {
if (curinclude.isActive() && !curinclude.isResolved()) {
ret.add(new Path(curinclude.getName()).removeFileExtension().toString());
}
}
}
} finally {
index.releaseReadLock();
}
} catch (CoreException e1) {
// ignore
e1.printStackTrace();
} catch (InterruptedException e) {
// ignore
e.printStackTrace();
}
return ret;
}
public static void checkLibraries(IProject affectedProject) {
ICProjectDescriptionManager mngr = CoreModel.getDefault().getProjectDescriptionManager();
if (mngr != null) {
ICProjectDescription projectDescription = mngr.getProjectDescription(affectedProject, true);
if (projectDescription != null) {
ICConfigurationDescription configurationDescription = projectDescription.getActiveConfiguration();
if (configurationDescription != null) {
Set<String> UnresolvedIncludedHeaders = getUnresolvedProjectIncludes(affectedProject);
Set<String> alreadyAddedLibs = getAllLibrariesFromProject(affectedProject);
Map<String, IPath> availableLibs = getAllInstalledLibraries(configurationDescription);
UnresolvedIncludedHeaders.removeAll(alreadyAddedLibs);
availableLibs.keySet().retainAll(UnresolvedIncludedHeaders);
if (!availableLibs.isEmpty()) {
// there are possible libraries to add
Common.log(new Status(IStatus.INFO, Const.CORE_PLUGIN_ID, "list of libraries to add to project " //$NON-NLS-1$
+ affectedProject.getName() + ": " + availableLibs.keySet().toString())); //$NON-NLS-1$
addLibrariesToProject(affectedProject, configurationDescription, availableLibs);
try {
mngr.setProjectDescription(affectedProject, projectDescription, true, null);
} catch (CoreException e) {
e.printStackTrace();
}
}
}
}
}
}
}