/*
* 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.libs;
import static com.google.common.collect.Lists.newArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.SubMonitor;
import org.rf.ide.core.executor.RobotRuntimeEnvironment;
import org.rf.ide.core.executor.RobotRuntimeEnvironment.RobotEnvironmentException;
import org.rf.ide.core.executor.SuiteExecutor;
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.rf.ide.core.project.RobotProjectConfig.RemoteLocation;
import org.robotframework.ide.eclipse.main.plugin.RedPlugin;
import org.robotframework.ide.eclipse.main.plugin.RedWorkspace;
import org.robotframework.ide.eclipse.main.plugin.model.LibspecsFolder;
import org.robotframework.ide.eclipse.main.plugin.model.RobotProject;
import org.robotframework.ide.eclipse.main.plugin.project.RedEclipseProjectConfig;
import org.robotframework.ide.eclipse.main.plugin.project.build.BuildLogger;
import org.robotframework.ide.eclipse.main.plugin.project.build.ProblemsReportingStrategy;
import org.robotframework.ide.eclipse.main.plugin.project.build.RobotProblem;
import org.robotframework.ide.eclipse.main.plugin.project.build.causes.ProjectConfigurationProblem;
import org.robotframework.ide.eclipse.main.plugin.project.library.LibrarySpecification;
import com.google.common.base.Objects;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
public class LibrariesBuilder {
private final BuildLogger logger;
public LibrariesBuilder(final BuildLogger logger) {
this.logger = logger;
}
public void forceLibrariesRebuild(final Multimap<IProject, LibrarySpecification> groupedSpecifications,
final SubMonitor monitor) {
monitor.subTask("generating libdocs");
final Multimap<IProject, GeneratorWithSource> groupedGenerators = LinkedHashMultimap.create();
for (final IProject project : groupedSpecifications.keySet()) {
for (final LibrarySpecification specification : groupedSpecifications.get(project)) {
final GeneratorWithSource generatorWithSource = new GeneratorWithSource(specification.getSourceFile(),
provideGenerator(specification));
groupedGenerators.put(project, generatorWithSource);
}
}
monitor.setWorkRemaining(groupedGenerators.size());
for (final IProject project : groupedGenerators.keySet()) {
final RobotProject robotProject = RedPlugin.getModelManager().createProject(project);
final RobotRuntimeEnvironment runtimeEnvironment = robotProject.getRuntimeEnvironment();
for (final GeneratorWithSource generatorWithSource : groupedGenerators.get(project)) {
monitor.subTask(generatorWithSource.generator.getMessage());
try {
if (project.exists()) {
generatorWithSource.generator.generateLibdocForcibly(runtimeEnvironment,
new RedEclipseProjectConfig(robotProject.getRobotProjectConfig())
.createEnvironmentSearchPaths(project));
}
} catch (final RobotEnvironmentException e) {
final IPath libspecFileLocation = generatorWithSource.sourceLibdocFile.getLocation();
if (libspecFileLocation != null) {
libspecFileLocation.toFile().delete();
}
throw e;
}
monitor.worked(1);
}
}
monitor.done();
}
private ILibdocGenerator provideGenerator(final LibrarySpecification specification) {
final IFile libspecSourceFile = specification.getSourceFile();
if (!specification.isReferenced() && !specification.isRemote()) {
return new StandardLibraryLibdocGenerator(libspecSourceFile);
} else if (!specification.isReferenced()) {
return new RemoteLibraryLibdocGenerator(specification.getRemoteLocation().getUriAddress(),
libspecSourceFile);
} else {
specification.setIsModified(false);
final String path = specification.getSecondaryKey();
final ReferencedLibrary refLib = specification.getReferencedLibrary();
final LibraryType type = refLib.provideType();
if (type == LibraryType.VIRTUAL) {
return new VirtualLibraryLibdocGenerator(Path.fromPortableString(path), libspecSourceFile);
} else if (type == LibraryType.PYTHON) {
final String libPath = RedWorkspace.Paths
.toAbsoluteFromWorkspaceRelativeIfPossible(Path.fromPortableString(refLib.getPath()))
.toOSString();
return new PythonLibraryLibdocGenerator(refLib.getName(), libPath, libspecSourceFile);
} else if (type == LibraryType.JAVA) {
final String libPath = RedWorkspace.Paths
.toAbsoluteFromWorkspaceRelativeIfPossible(Path.fromPortableString(path)).toOSString();
return new JavaLibraryLibdocGenerator(specification.getName(), libPath, libspecSourceFile);
}
throw new IllegalStateException("Unknown library type: " + type);
}
}
public void buildLibraries(final RobotProject robotProject, final RobotRuntimeEnvironment runtimeEnvironment,
final RobotProjectConfig configuration, final SubMonitor monitor,
final ProblemsReportingStrategy reporter) {
logger.log("BUILDING: generating library docs");
monitor.subTask("generating libdocs");
final List<ILibdocGenerator> libdocGenerators = newArrayList();
final LibspecsFolder libspecsFolder = LibspecsFolder.get(robotProject.getProject());
libdocGenerators.addAll(getStandardLibrariesToRecreate(runtimeEnvironment, libspecsFolder));
libdocGenerators.addAll(getReferencedVirtualLibrariesToRecreate(configuration, libspecsFolder));
libdocGenerators.addAll(getReferencedPythonLibrariesToRecreate(configuration, libspecsFolder));
if (runtimeEnvironment.getInterpreter() == SuiteExecutor.Jython) {
libdocGenerators.addAll(getReferencedJavaLibrariesToRecreate(configuration, libspecsFolder));
}
libdocGenerators.addAll(getRemoteLibrariesToRecreate(configuration, libspecsFolder));
monitor.setWorkRemaining(libdocGenerators.size());
for (final ILibdocGenerator generator : libdocGenerators) {
if (monitor.isCanceled()) {
return;
}
logger.log("BUILDING: " + generator.getMessage());
monitor.subTask(generator.getMessage());
try {
generator.generateLibdoc(runtimeEnvironment, new RedEclipseProjectConfig(configuration)
.createEnvironmentSearchPaths(robotProject.getProject()));
} catch (final RobotEnvironmentException e) {
final RobotProblem problem = RobotProblem.causedBy(
ProjectConfigurationProblem.LIBRARY_SPEC_CANNOT_BE_GENERATED).formatMessageWith(e.getMessage());
reporter.handleProblem(problem, robotProject.getFile(".project"), 1);
}
monitor.worked(1);
}
monitor.done();
}
private List<ILibdocGenerator> getStandardLibrariesToRecreate(final RobotRuntimeEnvironment runtimeEnvironment,
final LibspecsFolder libspecsFolder) {
final List<ILibdocGenerator> generators = newArrayList();
final List<String> stdLibs = runtimeEnvironment.getStandardLibrariesNames();
try {
final List<IFile> toRecr = libspecsFolder.collectSpecsWithDifferentVersion(stdLibs,
runtimeEnvironment.getVersion());
for (final IFile specToRecreate : toRecr) {
generators.add(new StandardLibraryLibdocGenerator(specToRecreate));
}
} catch (final CoreException e) {
// FIXME : handle this
e.printStackTrace();
}
return generators;
}
private List<ILibdocGenerator> getReferencedVirtualLibrariesToRecreate(
final RobotProjectConfig configuration, final LibspecsFolder libspecsFolder) {
final List<ILibdocGenerator> generators = newArrayList();
for (final ReferencedLibrary lib : configuration.getLibraries()) {
if (lib.provideType() == LibraryType.VIRTUAL) {
final Path libPath = new Path(lib.getPath());
if (libPath.isAbsolute()) {
final String libName = lib.getName();
final IFile specFile = libspecsFolder.getSpecFile(libName);
if (!specFile.exists()) {
generators.add(new VirtualLibraryLibdocGenerator(libPath, specFile));
}
}
}
}
return generators;
}
private List<ILibdocGenerator> getReferencedPythonLibrariesToRecreate(final RobotProjectConfig configuration,
final LibspecsFolder libspecsFolder) {
final List<ILibdocGenerator> generators = newArrayList();
for (final ReferencedLibrary lib : configuration.getLibraries()) {
if (lib.provideType() == LibraryType.PYTHON) {
final String libName = lib.getName();
final IFile specFile = libspecsFolder.getSpecFile(libName);
if (!specFile.exists()) {
final String libPath = RedWorkspace.Paths
.toAbsoluteFromWorkspaceRelativeIfPossible(Path.fromPortableString(lib.getPath()))
.toOSString();
generators.add(new PythonLibraryLibdocGenerator(libName, libPath, specFile));
}
}
}
return generators;
}
private List<ILibdocGenerator> getReferencedJavaLibrariesToRecreate(final RobotProjectConfig configuration,
final LibspecsFolder libspecsFolder) {
final List<ILibdocGenerator> generators = newArrayList();
for (final ReferencedLibrary lib : configuration.getLibraries()) {
if (lib.provideType() == LibraryType.JAVA) {
final String libName = lib.getName();
final IFile specFile = libspecsFolder.getSpecFile(libName);
if (!specFile.exists()) {
final String jarPath = RedWorkspace.Paths
.toAbsoluteFromWorkspaceRelativeIfPossible(Path.fromPortableString(lib.getPath()))
.toOSString();
generators.add(new JavaLibraryLibdocGenerator(libName, jarPath, specFile));
}
}
}
return generators;
}
private Collection<? extends ILibdocGenerator> getRemoteLibrariesToRecreate(final RobotProjectConfig configuration,
final LibspecsFolder libspecsFolder) {
final List<ILibdocGenerator> generators = newArrayList();
for (final RemoteLocation location : configuration.getRemoteLocations()) {
final IFile specFile = libspecsFolder.getSpecFile(location.createLibspecFileName());
if (!specFile.exists()) {
generators.add(new RemoteLibraryLibdocGenerator(location.getUriAddress(), specFile));
}
}
return generators;
}
private static final class GeneratorWithSource {
private final IFile sourceLibdocFile;
private final ILibdocGenerator generator;
GeneratorWithSource(final IFile source, final ILibdocGenerator generator) {
this.sourceLibdocFile = source;
this.generator = generator;
}
@Override
public boolean equals(final Object obj) {
if (obj != null && obj.getClass() == GeneratorWithSource.class) {
final GeneratorWithSource that = (GeneratorWithSource) obj;
return Objects.equal(this.sourceLibdocFile, that.sourceLibdocFile)
&& Objects.equal(this.getClass(), that.generator);
}
return false;
}
@Override
public int hashCode() {
return Objects.hashCode(sourceLibdocFile, generator);
}
}
}