/*
* Copyright 2015 Nokia Solutions and Networks
* Licensed under the Apache License, Version 2.0,
* see license.txt file for details.
*/
package org.robotframework.ide.eclipse.main.plugin.project.build.fix;
import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
import org.rf.ide.core.executor.EnvironmentSearchPaths;
import org.rf.ide.core.executor.RobotRuntimeEnvironment;
import org.rf.ide.core.executor.RobotRuntimeEnvironment.RobotEnvironmentException;
import org.rf.ide.core.project.ImportPath;
import org.rf.ide.core.project.ImportSearchPaths;
import org.rf.ide.core.project.ImportSearchPaths.PathsProvider;
import org.rf.ide.core.project.ResolvedImportPath;
import org.rf.ide.core.project.RobotProjectConfig;
import org.rf.ide.core.project.RobotProjectConfig.LibraryType;
import org.rf.ide.core.project.RobotProjectConfig.ReferencedLibrary;
import org.robotframework.ide.eclipse.main.plugin.RedImages;
import org.robotframework.ide.eclipse.main.plugin.RedPlugin;
import org.robotframework.ide.eclipse.main.plugin.model.RobotProject;
import org.robotframework.ide.eclipse.main.plugin.model.RobotSuiteFile;
import org.robotframework.ide.eclipse.main.plugin.project.LibrariesAutoDiscoverer;
import org.robotframework.ide.eclipse.main.plugin.project.RedEclipseProjectConfig;
import org.robotframework.ide.eclipse.main.plugin.project.RedProjectConfigEventData;
import org.robotframework.ide.eclipse.main.plugin.project.RobotProjectConfigEvents;
import org.robotframework.ide.eclipse.main.plugin.project.editor.RedProjectEditor;
import org.robotframework.ide.eclipse.main.plugin.project.editor.libraries.ReferencedLibraryImporter;
import org.robotframework.red.graphics.ImagesManager;
/**
* @author Michal Anglart
*
*/
public class AddLibraryToRedXmlFixer extends RedXmlConfigMarkerResolution {
private final String pathOrName;
private final boolean isPath;
public AddLibraryToRedXmlFixer(final String pathOrName, final boolean isPath) {
this.pathOrName = pathOrName;
this.isPath = isPath;
}
@Override
public String getLabel() {
return "Discover '" + pathOrName + "' and add to configuration";
}
@Override
protected ICompletionProposal asContentProposal(final IMarker marker, final IFile externalFile) {
final RobotSuiteFile file = RedPlugin.getModelManager().createSuiteFile((IFile) marker.getResource());
return new AddLibraryProposal(marker, file, externalFile, getLabel());
}
private class AddLibraryProposal extends RedConfigFileCompletionProposal {
private final RobotSuiteFile suiteFile;
private final Collection<ReferencedLibrary> addedLibraries = new ArrayList<>();
public AddLibraryProposal(final IMarker marker, final RobotSuiteFile suiteFile, final IFile externalFile,
final String shortDescription) {
super(marker, externalFile, shortDescription, null);
this.suiteFile = suiteFile;
}
@Override
public boolean apply(final IFile externalFile, final RobotProjectConfig config)
throws ProposalApplyingException {
return isPath ? importLibraryByPath(config, pathOrName) : importLibraryByName(externalFile, config);
}
private boolean importLibraryByName(final IFile externalFile, final RobotProjectConfig config) {
final RobotProject project = RedPlugin.getModelManager().createProject(externalFile.getProject());
final RobotRuntimeEnvironment env = project.getRuntimeEnvironment();
Optional<File> modulePath = Optional.empty();
try {
final String currentFileDirectoryPath = suiteFile.getFile().getParent().getLocation().toOSString();
final EnvironmentSearchPaths searchPaths = new RedEclipseProjectConfig(config)
.createEnvironmentSearchPaths(project.getProject());
searchPaths.addPythonPath(currentFileDirectoryPath);
searchPaths.addClassPath(currentFileDirectoryPath);
modulePath = env.getModulePath(pathOrName, searchPaths);
if (!modulePath.isPresent()) {
throw new RobotEnvironmentException("No path found");
}
if (modulePath.get().getAbsolutePath().endsWith(".jar")) {
final IPath resolvedAbsPath = new Path(modulePath.get().getAbsolutePath());
final ReferencedLibraryImporter importer = new ReferencedLibraryImporter();
final RobotProject robotProject = suiteFile.getProject();
addedLibraries.addAll(importer.importJavaLib(Display.getCurrent().getActiveShell(),
robotProject.getRuntimeEnvironment(), robotProject.getProject(), config,
resolvedAbsPath.toString()));
if (addedLibraries.isEmpty()) {
throw new ProposalApplyingException("Unable to apply proposal");
} else {
for (final ReferencedLibrary addedLibrary : addedLibraries) {
config.addReferencedLibrary(addedLibrary);
}
return true;
}
} else {
final File moduleFile = modulePath.get();
if (moduleFile.isDirectory()
&& new File(moduleFile.getPath() + File.separator + "__init__.py").exists()) {
final ReferencedLibrary newLibrary = ReferencedLibrary.create(LibraryType.PYTHON, pathOrName,
new Path(moduleFile.getPath()).toPortableString());
addedLibraries.add(newLibrary);
config.addReferencedLibrary(newLibrary);
return true;
} else {
return importLibraryByPath(config, moduleFile.getAbsolutePath());
}
}
} catch (final RobotEnvironmentException e) {
final List<IResource> suitesList = new ArrayList<>();
suitesList.add(suiteFile.getFile());
new LibrariesAutoDiscoverer(project, suitesList, eventBroker, pathOrName).start();
return false;
}
}
private boolean importLibraryByPath(final RobotProjectConfig config, final String path) {
if (path.endsWith("/") || path.endsWith(".py")) {
final Map<String, String> vars = suiteFile.getProject().getRobotProjectHolder().getVariableMappings();
final ResolvedImportPath resolvedPath = ResolvedImportPath.from(ImportPath.from(path), vars).get();
final PathsProvider pathsProvider = suiteFile.getProject().createPathsProvider();
final Optional<URI> absolutePath = new ImportSearchPaths(pathsProvider)
.findAbsoluteUri(suiteFile.getFile().getLocationURI(), resolvedPath);
if (!absolutePath.isPresent()) {
MessageDialog.openError(Display.getCurrent().getActiveShell(), "Library import problem",
"Unable to find library under '" + path + "' location.");
return false;
}
final ReferencedLibraryImporter importer = new ReferencedLibraryImporter();
final RobotProject robotProject = suiteFile.getProject();
addedLibraries.addAll(importer.importPythonLib(Display.getCurrent().getActiveShell(),
robotProject.getRuntimeEnvironment(), robotProject.getProject(), config,
new File(absolutePath.get()).getAbsolutePath()));
if (addedLibraries.isEmpty()) {
throw new ProposalApplyingException("Unable to apply proposal");
} else {
for (final ReferencedLibrary addedLibrary : addedLibraries) {
config.addReferencedLibrary(addedLibrary);
}
return true;
}
} else {
MessageDialog.openError(Display.getCurrent().getActiveShell(), "Library import problem",
"The path '" + path + "' should point to either .py file or python module directory.");
return false;
}
}
@Override
protected void openDesiredPageInEditor(final RedProjectEditor editor) {
editor.openLibrariesPage();
}
@Override
protected void fireEvents() {
if (!addedLibraries.isEmpty()) {
final RedProjectConfigEventData<Collection<ReferencedLibrary>> eventData = new RedProjectConfigEventData<>(
externalFile, addedLibraries);
eventBroker.send(RobotProjectConfigEvents.ROBOT_CONFIG_LIBRARIES_STRUCTURE_CHANGED, eventData);
}
}
@Override
public String getAdditionalProposalInfo() {
return isPath ? "Add '" + pathOrName + "' location to red.xml file"
: "Try to discover location of '" + pathOrName + "' library and add it to red.xml file";
}
@Override
public Image getImage() {
return ImagesManager.getImage(RedImages.getMagnifierImage());
}
}
}